├── .gitignore ├── README.md └── formal-version ├── dp-upf-ctrl.py ├── multi-sdn-topo.py ├── nfv-embb-ctrl.py ├── nfv-mmtc-ctrl.py ├── nfv-urllc-ctrl.py ├── sba-af-ctrl.py ├── sba-amf-ctrl.py ├── sba-ausf-ctrl.py ├── sba-nrf-ctrl.py ├── sba-pcf-ctrl.py ├── sba-smf-ctrl.py ├── sba-udm-ctrl.py ├── servers ├── d_DN.py ├── d_UPF_h0.py ├── n_URLLC_h0.py ├── n_eMBB_h0.py ├── n_mMTC_h0.py ├── s_AF_h0.py ├── s_AMF_h0.py ├── s_AUSF_h0.py ├── s_NRF_h0.py ├── s_PCF_h0.py ├── s_SMF_h0.py ├── s_UDM_h0.py ├── uam_h0.py ├── ue_URLLC_h.py ├── ue_eMBB_h.py └── ue_mMTC_h.py └── ue-access-ctrl.py /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | *.pyc 3 | test/* 4 | *.sh -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SDN-based Network Slicing Platform of 5G Core Network 2 | An SDN-based solution of Network Slicing in 5G Service Based Architecture (SBA) core network, constructed with multiple SDN subsystems. With full SBA Entities implementation, we can provide network slices of 5G scenarios (URLLC, eMBB, mMTC) for 5G UEs to comsume SBA core network resources. 3 | ## Features 4 | * Built with multiple SDN controller-switch subsystems 5 | * Easy to scale and load balance inside subsystems, and free to add new subsystems into the platform 6 | * Same structure of 5G core network and transmitting protocols as 3GPP defines 7 | ## Table of Contents 8 | * [Getting Started](#getting-started) 9 | * [Requirements](#requirements) 10 | * [Dependencies](#dependencies) 11 | * [Installation](#installation) 12 | * [Deployment](#deployment) 13 | * [Running](#running) 14 | * [Authors](#authors) 15 | * [Declaration](#declaration) 16 | ## Getting Started 17 | ### Requirements 18 | * Ubuntu 14.04↑ 19 | * Python 2.7 (2.7.12↑) 20 | ### Dependencies 21 | * [Mininet](https://github.com/mininet/mininet) 2.2.1 -> SDN Topology Emulator 22 | * [Ryu](https://github.com/osrg/ryu) 4.32 -> Openflow Controller Framework 23 | * [hyper-h2](https://github.com/python-hyper/hyper-h2) 2.6.2 -> HTTP/2 Server Framework 24 | * [hyper](https://github.com/python-hyper/hyper) 0.7.0 -> HTTP/2 Client Framework 25 | ### Installation 26 | Just clone it into your host 27 | ``` 28 | git clone https://gitlab.com/jercymat/qualcomm-proj.git 29 | ``` 30 | ## Deployment 31 | Clone to your ubuntu host, and make sure that all the dependencies are installed. 32 | 1. **Start up Mininet topology** 33 | ``` 34 | cd qualcomm-proj/formal-version 35 | sudo ./multi-sdn-topo.py 36 | ``` 37 | 2. **Start up Ryu SDN controllers** 38 | 39 | There are 12 SDN subsystems constructing the whole system, which means there are 12 Ryu controllers to start. 40 | 41 | If you want to run them in background: 42 | ``` 43 | ryu-manager ue-access-ctrl.py --ofp-tcp-listen-port 6661 --wsapi-port 6662 & 44 | 45 | ryu-manager nfv-urllc-ctrl.py --ofp-tcp-listen-port 6671 --wsapi-port 6672 & 46 | ryu-manager nfv-embb-ctrl.py --ofp-tcp-listen-port 6681 --wsapi-port 6682 & 47 | ryu-manager nfv-mmtc-ctrl.py --ofp-tcp-listen-port 6691 --wsapi-port 6692 & 48 | 49 | ryu-manager sba-nrf-ctrl.py --ofp-tcp-listen-port 7011 --wsapi-port 7012 & 50 | ryu-manager sba-ausf-ctrl.py --ofp-tcp-listen-port 7021 --wsapi-port 7022 & 51 | ryu-manager sba-udm-ctrl.py --ofp-tcp-listen-port 7031 --wsapi-port 7032 & 52 | ryu-manager sba-amf-ctrl.py --ofp-tcp-listen-port 7041 --wsapi-port 7042 & 53 | ryu-manager sba-smf-ctrl.py --ofp-tcp-listen-port 7051 --wsapi-port 7052 & 54 | ryu-manager sba-pcf-ctrl.py --ofp-tcp-listen-port 7061 --wsapi-port 7062 & 55 | ryu-manager sba-af-ctrl.py --ofp-tcp-listen-port 7071 --wsapi-port 7072 & 56 | 57 | ryu-manager dp-upf-ctrl.py --ofp-tcp-listen-port 8001 --wsapi-port 8002 & 58 | ``` 59 | You can also open a new terminal window for each controller, just type the command above one line per window, but take the trailing `&` off. 60 | 61 | It's highly recommended to use [tmux](https://github.com/tmux/tmux). 62 | 63 | 3. **Start up host servers** 64 | 65 | Each subsystem has a server to handle incoming requests, start them in mininet command line: 66 | ``` 67 | uam_h0 python ./servers/uam_h0.py & 68 | 69 | n_URLLC_h0 python ./servers/n_URLLC_h0.py & 70 | n_eMBB_h0 python ./servers/n_eMBB_h0.py & 71 | n_mMTC_h0 python ./servers/n_mMTC_h0.py & 72 | 73 | s_NRF_h0 python ./servers/s_NRF_h0.py & 74 | s_AUSF_h0 python ./servers/s_AUSF_h0.py & 75 | s_UDM_h0 python ./servers/s_UDM_h0.py & 76 | s_AMF_h0 python ./servers/s_AMF_h0.py & 77 | s_SMF_h0 python ./servers/s_SMF_h0.py & 78 | s_PCF_h0 python ./servers/s_PCF_h0.py & 79 | s_AF_h0 python ./servers/s_AF_h0.py & 80 | 81 | d_UPF_h0 python ./servers/d_UPF_h0.py & 82 | d_DN_h0 python ./servers/d_DN_h0.py & 83 | ``` 84 | Now your system is ready for sending packets. 85 | ## Running 86 | You can now send packets, run the UEs in mininet command line: 87 | 88 | **URLLC Scenario** 89 | ``` 90 | ue_URLLC_h python ./servers/ue_URLLC_h 91 | ``` 92 | **eMBB Scenario** 93 | ``` 94 | ue_eMBB_h python ./servers/ue_eMBB_h 95 | ``` 96 | **mMTC Scenario** 97 | ``` 98 | ue_mMTC_h python ./servers/ue_mMTC_h 99 | ``` 100 | Enjoy. 101 | ## Authors 102 | * **Han-Hsuan Lin** - *Dept. of computer science, National Chengchi University* - [105703004@nccu.edu.tw](mailto:105703004@nccu.edu.tw) 103 | * **Yu-Chiao Hsu** - *Dept. of computer science, National Chengchi University* - [104753036@nccu.edu.tw](mailto:104753036@nccu.edu.tw) 104 | ## Declaration 105 | This system is built for Qualcomm Taiwan University Research Program. -------------------------------------------------------------------------------- /formal-version/dp-upf-ctrl.py: -------------------------------------------------------------------------------- 1 | from ryu.base import app_manager 2 | from ryu.controller import ofp_event 3 | from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER 4 | from ryu.controller.handler import set_ev_cls 5 | from ryu.ofproto import ofproto_v1_3 6 | from ryu.lib.packet import packet 7 | from ryu.lib.packet import ethernet, ether_types, arp 8 | 9 | # REST Api Packages 10 | import json 11 | import logging 12 | from ryu.app.wsgi import WSGIApplication, ControllerBase, route 13 | from webob import Response 14 | 15 | dp_instance_name = 'DP_UPF' 16 | 17 | 18 | class DPupfCtrl(app_manager.RyuApp): 19 | OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] 20 | _CONTEXTS = {'wsgi': WSGIApplication} 21 | 22 | def __init__(self, *args, **kwargs): 23 | super(DPupfCtrl, self).__init__(*args, **kwargs) 24 | self.mac_to_port = {} # mac address to inbound port table 25 | self.arp_broadcast = {} # arp broadcast inbound port table 26 | wsgi = kwargs['wsgi'] 27 | wsgi.register(EastWestAPI, {dp_instance_name: self}) 28 | 29 | @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER) 30 | def switch_features_handler(self, ev): 31 | datapath = ev.msg.datapath 32 | ofproto = datapath.ofproto 33 | parser = datapath.ofproto_parser 34 | 35 | # install table-miss flow entry 36 | # 37 | # We specify NO BUFFER to max_len of the output action due to 38 | # OVS bug. At this moment, if we specify a lesser number, e.g., 39 | # 128, OVS will send Packet-In with invalid buffer_id and 40 | # truncated packet data. In that case, we cannot output packets 41 | # correctly. The bug has been fixed in OVS v2.1.0. 42 | match = parser.OFPMatch() 43 | actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, 44 | ofproto.OFPCML_NO_BUFFER)] 45 | self.add_flow(datapath, 0, match, actions) 46 | 47 | def add_flow(self, datapath, priority, match, actions, buffer_id=None): 48 | ofproto = datapath.ofproto 49 | parser = datapath.ofproto_parser 50 | 51 | inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, 52 | actions)] 53 | if buffer_id: 54 | mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id, 55 | priority=priority, match=match, 56 | instructions=inst) 57 | else: 58 | mod = parser.OFPFlowMod(datapath=datapath, priority=priority, 59 | match=match, instructions=inst) 60 | datapath.send_msg(mod) 61 | 62 | @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) 63 | def _packet_in_handler(self, ev): 64 | # If you hit this you might want to increase 65 | # the "miss_send_length" of your switch 66 | if ev.msg.msg_len < ev.msg.total_len: 67 | self.logger.debug("packet truncated: only %s of %s bytes", 68 | ev.msg.msg_len, ev.msg.total_len) 69 | msg = ev.msg 70 | datapath = msg.datapath 71 | ofproto = datapath.ofproto 72 | parser = datapath.ofproto_parser 73 | in_port = msg.match['in_port'] 74 | 75 | pkt = packet.Packet(msg.data) 76 | eth = pkt.get_protocols(ethernet.ethernet)[0] 77 | dst = eth.dst 78 | src = eth.src 79 | dpid = datapath.id 80 | 81 | # ignore lldp and ipv6 packet 82 | if eth.ethertype == ether_types.ETH_TYPE_LLDP or eth.ethertype == ether_types.ETH_TYPE_IPV6: 83 | return 84 | 85 | self.logger.info("Packet In: %s %s -> %s | port:%s", 86 | dpid, src, dst, in_port) 87 | 88 | if eth.ethertype == ether_types.ETH_TYPE_ARP and dst == "ff:ff:ff:ff:ff:ff": 89 | arp_dst_ip = pkt.get_protocol(arp.arp).dst_ip 90 | if (dpid, src, arp_dst_ip) in self.arp_broadcast: 91 | if self.arp_broadcast[(dpid, src, arp_dst_ip)] != in_port: 92 | out = datapath.ofproto_parser.OFPPacketOut( 93 | datapath=datapath, 94 | buffer_id=datapath.ofproto.OFP_NO_BUFFER, 95 | in_port=in_port, 96 | actions=[], data=None) 97 | datapath.send_msg(out) 98 | self.logger.info('ARP Loop Maker Dropped!') 99 | 100 | return 101 | else: # learn arp broadcast table 102 | self.arp_broadcast[(dpid, src, arp_dst_ip)] = in_port 103 | 104 | self.mac_to_port.setdefault(dpid, {}) 105 | # learn a mac address to avoid FLOOD next time. 106 | self.mac_to_port[dpid][src] = in_port 107 | 108 | if dst in self.mac_to_port[dpid]: 109 | out_port = self.mac_to_port[dpid][dst] 110 | else: 111 | out_port = ofproto.OFPP_FLOOD 112 | 113 | actions = [parser.OFPActionOutput(out_port)] 114 | 115 | # install a flow to avoid packet_in next time 116 | if out_port != ofproto.OFPP_FLOOD: 117 | match = parser.OFPMatch(in_port=in_port, eth_dst=dst, eth_src=src) 118 | # verify if we have a valid buffer_id, if yes avoid to send both 119 | # flow_mod & packet_out 120 | if msg.buffer_id != ofproto.OFP_NO_BUFFER: 121 | self.add_flow(datapath, 1, match, actions, msg.buffer_id) 122 | return 123 | else: 124 | self.add_flow(datapath, 1, match, actions) 125 | data = None 126 | if msg.buffer_id == ofproto.OFP_NO_BUFFER: 127 | data = msg.data 128 | 129 | out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id, 130 | in_port=in_port, actions=actions, data=data) 131 | datapath.send_msg(out) 132 | 133 | 134 | class EastWestAPI(ControllerBase): 135 | def __init__(self, req, link, data, **config): 136 | super(EastWestAPI, self).__init__(req, link, data, **config) 137 | self.UPF_app = data[dp_instance_name] 138 | self.logger = logging.getLogger(self.__class__.__name__) 139 | self.authentication = { 140 | 'TEST': '033bd94b1168d7e4f0d644c3c95e35bf', 141 | 'URLLC': 'dfdc323ef40c8f38f5f022a5554f2dee', 142 | 'EMBB': 'e9406f9b456569f230a23d21464189f2', 143 | 'MMTC': '1d99331a7879c3c5b90998f8c3c6a9d6' 144 | } 145 | self.unauthenticated = Response( 146 | status=401, 147 | content_type='application/json', 148 | body=json.dumps( 149 | {'error': 'unauthenticated'}, 150 | indent=4 151 | ) + '\n' 152 | ) 153 | 154 | @route('mac-port-table', '/mac-port-table', methods=['GET']) 155 | def _mac_port_table(self, req, **kwargs): 156 | UPF_app = self.UPF_app 157 | body = json.dumps(UPF_app.mac_to_port, indent=4) + '\n' 158 | 159 | if 'Authentication' in req.headers: 160 | if req.headers['Authentication'] in self.authentication.values(): 161 | return Response(content_type='application/json', body=body) 162 | else: 163 | return self.unauthenticated 164 | else: 165 | return self.unauthenticated 166 | 167 | @route('arp-table', '/arp-table', methods=['GET']) 168 | def _arp_table(self, req, **kwargs): 169 | arp_broadcast = self.UPF_app.arp_broadcast 170 | arp_str_table = {} 171 | for key in arp_broadcast.keys(): 172 | arp_str_table[str(key)] = arp_broadcast[key] 173 | body = json.dumps(arp_str_table, indent=4) + '\n' 174 | 175 | if 'Authentication' in req.headers: 176 | if req.headers['Authentication'] in self.authentication.values(): 177 | return Response(content_type='application/json', body=body) 178 | else: 179 | return self.unauthenticated 180 | else: 181 | return self.unauthenticated 182 | -------------------------------------------------------------------------------- /formal-version/multi-sdn-topo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from mininet.net import Mininet 4 | from mininet.node import OVSSwitch, RemoteController 5 | from mininet.cli import CLI 6 | from mininet.link import TCLink 7 | from mininet.log import setLogLevel, info 8 | 9 | # import mininet.ns3 10 | # from mininet.ns3 import SimpleLink 11 | 12 | controllers = {} 13 | switches = {} 14 | hosts = {} 15 | 16 | dpid_cnt = 1 17 | 18 | 19 | def DistrubutedSBANet(): 20 | "initialize network" 21 | info('-----------------------------------------\n') 22 | info('| Distributed SDN-based 5G Core Network |\n') 23 | info('| Qualcomm Project 2019/6-2019/12 |\n') 24 | info('| Yu Chiao Hsu, Han Hsuan Lin |\n') 25 | info('-----------------------------------------\n') 26 | 27 | net = Mininet(controller=None, switch=OVSSwitch, 28 | link=TCLink, autoSetMacs=True) 29 | 30 | # UE Access Component 31 | ue_access_component(net, 6661) 32 | 33 | # NFV Service Component 34 | nfv_service_component(net, 'URLLC', 6671, 1) 35 | nfv_service_component(net, 'eMBB', 6681, 2) 36 | nfv_service_component(net, 'mMTC', 6691, 3) 37 | 38 | # SBA Entity Component 39 | sba_entity_component(net, 'NRF', 7011, 1) 40 | sba_entity_component(net, 'AUSF', 7021, 2) 41 | sba_entity_component(net, 'UDM', 7031, 3) 42 | sba_entity_component(net, 'AMF', 7041, 4) 43 | sba_entity_component(net, 'SMF', 7051, 5, switch_cnt=2) 44 | sba_entity_component(net, 'PCF', 7061, 6) 45 | sba_entity_component(net, 'AF', 7071, 7) 46 | 47 | # Data Plane 48 | data_plane(net, 8001) 49 | 50 | # Link UAM switch to NFV Services' controllers 51 | net.addLink(switches['uam'][0], switches['n_URLLC'][0]) 52 | net.addLink(switches['uam'][0], switches['n_eMBB'][0]) 53 | net.addLink(switches['uam'][0], switches['n_mMTC'][0]) 54 | 55 | # Link NFV Services to AMF 56 | net.addLink(switches['n_URLLC'][0], switches['s_AMF'][0]) 57 | net.addLink(switches['n_eMBB'][0], switches['s_AMF'][0]) 58 | net.addLink(switches['n_mMTC'][0], switches['s_AMF'][0]) 59 | 60 | # Link SBA Entities as a chain 61 | net.addLink(switches['s_AMF'][0], switches['s_UDM'][0]) 62 | net.addLink(switches['s_UDM'][0], switches['s_AUSF'][0]) 63 | net.addLink(switches['s_AUSF'][0], switches['s_NRF'][0]) 64 | net.addLink(switches['s_AMF'][0], switches['s_SMF'][0]) 65 | net.addLink(switches['s_SMF'][0], switches['s_PCF'][0]) 66 | net.addLink(switches['s_PCF'][0], switches['s_AF'][0]) 67 | 68 | # Link Control Plane and Data Plane 69 | net.addLink(switches['s_SMF'][1], switches['d_UPF'][0]) 70 | net.addLink(switches['uam'][0], switches['d_UPF'][0]) 71 | 72 | # Add UE 73 | add_ue(net, 'URLLC', '10.0.1.101') 74 | add_ue(net, 'eMBB', '10.0.1.102') 75 | add_ue(net, 'mMTC', '10.0.1.103') 76 | 77 | return net 78 | 79 | 80 | def add_ue(net, name, ip='10.0.0.101'): 81 | "add UE" 82 | 83 | # add UE host 84 | hosts['ue_' + name] = [ 85 | net.addHost('ue_' + name + '_h', ip=ip) 86 | ] 87 | 88 | # link UE host to UAM 89 | net.addLink(switches['uam'][0], hosts['ue_' + name][0]) 90 | 91 | 92 | def ue_access_component(net, controller_port=6661): 93 | "add UE Access Component topo" 94 | 95 | info('*** Starting UE Access Controller at {}\n'.format(controller_port)) 96 | add_subsystem(net, 'uam', controller_port, '10.0.1.1', 1) 97 | 98 | 99 | def nfv_service_component(net, scenario=None, controller_port=6671, no=1): 100 | "add NFV Service Component topo" 101 | if not scenario: 102 | info('*** NFV Scenario Missing ***\n') 103 | return 104 | 105 | info('*** Starting NFV Service-{} Controller at {}\n'.format(scenario, controller_port)) 106 | add_subsystem(net, 'n_' + scenario, controller_port, 107 | '10.0.2.' + str(no), 1) 108 | 109 | 110 | def sba_entity_component(net, name=None, controller_port=7011, no=1, switch_cnt=1): 111 | "add SBA Entity Component topo" 112 | if not name: 113 | info('*** SBA Entity Name Missing ***\n') 114 | return 115 | 116 | info('*** Starting SBA Entity-{} Controller at {}\n'.format(name, controller_port)) 117 | add_subsystem(net, 's_' + name, controller_port, 118 | '10.0.3.' + str(no), switch_cnt) 119 | 120 | 121 | def data_plane(net, controller_port=8001): 122 | "add data plane topo for experiment" 123 | 124 | info('*** Starting data plane\n') 125 | info('*** Starting UPF Controller at {}\n'.format(controller_port)) 126 | add_subsystem(net, 'd_UPF', controller_port, '10.0.4.1', 1) 127 | hosts['d_UPF'].append(net.addHost('d_DN', ip='10.0.5.1')) 128 | net.addLink(switches['d_UPF'][0], hosts['d_UPF'][1]) 129 | 130 | 131 | def add_subsystem(net, name=None, controller_port=6661, host_ip='10.0.0.1', switch_cnt=1): 132 | "Add a SDN-based subsystem" 133 | global dpid_cnt 134 | 135 | if not name: 136 | info('*** Subsystem Name Missing ***\n') 137 | return 138 | 139 | controllers[name] = net.addController( 140 | name + '_c0', 141 | controller=RemoteController, 142 | port=controller_port 143 | ) 144 | # switches[name] = [ 145 | # net.addSwitch(name + '_s{}'.format(i), dpid=str(dpid_cnt)) 146 | # for i in range(switch_cnt) 147 | # ] 148 | switches[name] = [] 149 | for i in range(switch_cnt): 150 | switches[name].append(net.addSwitch(name + '_s{}'.format(i), dpid=hex(dpid_cnt)[2:])) 151 | dpid_cnt += 1 152 | hosts[name] = [ 153 | net.addHost(name + '_h0', ip=host_ip) 154 | ] 155 | 156 | # Add link between switch and host 157 | net.addLink(switches[name][0], hosts[name][0]) 158 | 159 | # Add link between all switches: 160 | if switch_cnt > 1: 161 | for i in range(switch_cnt - 1): 162 | for j in range(i + 1, switch_cnt): 163 | net.addLink(switches[name][i], switches[name][j]) 164 | 165 | 166 | if __name__ == "__main__": 167 | setLogLevel('info') 168 | 169 | net = DistrubutedSBANet() 170 | 171 | info('*** Starting Distributed SDN-based 5G Core Network\n') 172 | net.build() 173 | 174 | # Start controllers 175 | for k, c in controllers.items(): 176 | c.start() 177 | 178 | # Start switches with their controller 179 | for k, comp in switches.items(): 180 | for switch in comp: 181 | switch.start([controllers[k]]) 182 | # switch.start([]) 183 | 184 | # mininet.ns3.start() 185 | 186 | # info('*** Dumping all Controller, Switch and Hosts\n') 187 | # print controllers 188 | # print switches 189 | # print hosts 190 | 191 | # info('*** Testing Hosts') 192 | # net.pingAll() 193 | 194 | info('*** Running CLI\n') 195 | # info(pprint.pformat(controllers, indent=4) + '\n') 196 | # info(pprint.pformat(switches, indent=4) + '\n') 197 | # info(pprint.pformat(hosts, indent=4) + '\n') 198 | cli = CLI(net) 199 | cli.do_sh('uam_h0 echo hello') 200 | 201 | info('*** Stopping network\n') 202 | # mininet.ns3.clear() 203 | net.stop() 204 | -------------------------------------------------------------------------------- /formal-version/nfv-embb-ctrl.py: -------------------------------------------------------------------------------- 1 | from ryu.base import app_manager 2 | from ryu.controller import ofp_event 3 | from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER 4 | from ryu.controller.handler import set_ev_cls 5 | from ryu.ofproto import ofproto_v1_3 6 | from ryu.lib.packet import packet 7 | from ryu.lib.packet import ethernet, ether_types, arp 8 | 9 | # REST Api Packages 10 | import json 11 | import logging 12 | from ryu.app.wsgi import WSGIApplication, ControllerBase, route 13 | from webob import Response 14 | 15 | ue_instance_name = 'NFV_eMBB' 16 | 17 | 18 | class NFVembbCtrl(app_manager.RyuApp): 19 | OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] 20 | _CONTEXTS = {'wsgi': WSGIApplication} 21 | 22 | def __init__(self, *args, **kwargs): 23 | super(NFVembbCtrl, self).__init__(*args, **kwargs) 24 | self.mac_to_port = {} # mac address to inbound port table 25 | self.arp_broadcast = {} # arp broadcast inbound port table 26 | wsgi = kwargs['wsgi'] 27 | wsgi.register(EastWestAPI, {ue_instance_name: self}) 28 | 29 | @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER) 30 | def switch_features_handler(self, ev): 31 | datapath = ev.msg.datapath 32 | ofproto = datapath.ofproto 33 | parser = datapath.ofproto_parser 34 | 35 | # install table-miss flow entry 36 | # 37 | # We specify NO BUFFER to max_len of the output action due to 38 | # OVS bug. At this moment, if we specify a lesser number, e.g., 39 | # 128, OVS will send Packet-In with invalid buffer_id and 40 | # truncated packet data. In that case, we cannot output packets 41 | # correctly. The bug has been fixed in OVS v2.1.0. 42 | match = parser.OFPMatch() 43 | actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, 44 | ofproto.OFPCML_NO_BUFFER)] 45 | self.add_flow(datapath, 0, match, actions) 46 | 47 | def add_flow(self, datapath, priority, match, actions, buffer_id=None): 48 | ofproto = datapath.ofproto 49 | parser = datapath.ofproto_parser 50 | 51 | inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, 52 | actions)] 53 | if buffer_id: 54 | mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id, 55 | priority=priority, match=match, 56 | instructions=inst) 57 | else: 58 | mod = parser.OFPFlowMod(datapath=datapath, priority=priority, 59 | match=match, instructions=inst) 60 | datapath.send_msg(mod) 61 | 62 | @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) 63 | def _packet_in_handler(self, ev): 64 | # If you hit this you might want to increase 65 | # the "miss_send_length" of your switch 66 | if ev.msg.msg_len < ev.msg.total_len: 67 | self.logger.debug("packet truncated: only %s of %s bytes", 68 | ev.msg.msg_len, ev.msg.total_len) 69 | msg = ev.msg 70 | datapath = msg.datapath 71 | ofproto = datapath.ofproto 72 | parser = datapath.ofproto_parser 73 | in_port = msg.match['in_port'] 74 | 75 | pkt = packet.Packet(msg.data) 76 | eth = pkt.get_protocols(ethernet.ethernet)[0] 77 | dst = eth.dst 78 | src = eth.src 79 | dpid = datapath.id 80 | 81 | # ignore lldp and ipv6 packet 82 | if eth.ethertype == ether_types.ETH_TYPE_LLDP or eth.ethertype == ether_types.ETH_TYPE_IPV6: 83 | return 84 | 85 | self.logger.info("Packet In: %s %s -> %s | port:%s", 86 | dpid, src, dst, in_port) 87 | 88 | if eth.ethertype == ether_types.ETH_TYPE_ARP and dst == "ff:ff:ff:ff:ff:ff": 89 | arp_dst_ip = pkt.get_protocol(arp.arp).dst_ip 90 | if (dpid, src, arp_dst_ip) in self.arp_broadcast: 91 | if self.arp_broadcast[(dpid, src, arp_dst_ip)] != in_port: 92 | out = datapath.ofproto_parser.OFPPacketOut( 93 | datapath=datapath, 94 | buffer_id=datapath.ofproto.OFP_NO_BUFFER, 95 | in_port=in_port, 96 | actions=[], data=None) 97 | datapath.send_msg(out) 98 | self.logger.info('ARP Loop Maker Dropped!') 99 | 100 | return 101 | else: # learn arp broadcast table 102 | self.arp_broadcast[(dpid, src, arp_dst_ip)] = in_port 103 | 104 | self.mac_to_port.setdefault(dpid, {}) 105 | # learn a mac address to avoid FLOOD next time. 106 | self.mac_to_port[dpid][src] = in_port 107 | 108 | if dst in self.mac_to_port[dpid]: 109 | out_port = self.mac_to_port[dpid][dst] 110 | else: 111 | out_port = ofproto.OFPP_FLOOD 112 | 113 | actions = [parser.OFPActionOutput(out_port)] 114 | 115 | # install a flow to avoid packet_in next time 116 | if out_port != ofproto.OFPP_FLOOD: 117 | match = parser.OFPMatch(in_port=in_port, eth_dst=dst, eth_src=src) 118 | # verify if we have a valid buffer_id, if yes avoid to send both 119 | # flow_mod & packet_out 120 | if msg.buffer_id != ofproto.OFP_NO_BUFFER: 121 | self.add_flow(datapath, 1, match, actions, msg.buffer_id) 122 | return 123 | else: 124 | self.add_flow(datapath, 1, match, actions) 125 | data = None 126 | if msg.buffer_id == ofproto.OFP_NO_BUFFER: 127 | data = msg.data 128 | 129 | out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id, 130 | in_port=in_port, actions=actions, data=data) 131 | datapath.send_msg(out) 132 | 133 | 134 | class EastWestAPI(ControllerBase): 135 | def __init__(self, req, link, data, **config): 136 | super(EastWestAPI, self).__init__(req, link, data, **config) 137 | self.eMBB_app = data[ue_instance_name] 138 | self.logger = logging.getLogger(self.__class__.__name__) 139 | self.authentication = { 140 | 'TEST': '033bd94b1168d7e4f0d644c3c95e35bf', 141 | 'URLLC': 'dfdc323ef40c8f38f5f022a5554f2dee', 142 | 'EMBB': 'e9406f9b456569f230a23d21464189f2', 143 | 'MMTC': '1d99331a7879c3c5b90998f8c3c6a9d6' 144 | } 145 | self.unauthenticated = Response( 146 | status=401, 147 | content_type='application/json', 148 | body=json.dumps( 149 | {'error': 'unauthenticated'}, 150 | indent=4 151 | ) + '\n' 152 | ) 153 | 154 | @route('mac-port-table', '/mac-port-table', methods=['GET']) 155 | def _mac_port_table(self, req, **kwargs): 156 | eMBB_app = self.eMBB_app 157 | body = json.dumps(eMBB_app.mac_to_port, indent=4) + '\n' 158 | 159 | if 'Authentication' in req.headers: 160 | if req.headers['Authentication'] in self.authentication.values(): 161 | return Response(content_type='application/json', body=body) 162 | else: 163 | return self.unauthenticated 164 | else: 165 | return self.unauthenticated 166 | 167 | @route('arp-table', '/arp-table', methods=['GET']) 168 | def _arp_table(self, req, **kwargs): 169 | arp_broadcast = self.eMBB_app.arp_broadcast 170 | arp_str_table = {} 171 | for key in arp_broadcast.keys(): 172 | arp_str_table[str(key)] = arp_broadcast[key] 173 | body = json.dumps(arp_str_table, indent=4) + '\n' 174 | 175 | if 'Authentication' in req.headers: 176 | if req.headers['Authentication'] in self.authentication.values(): 177 | return Response(content_type='application/json', body=body) 178 | else: 179 | return self.unauthenticated 180 | else: 181 | return self.unauthenticated 182 | -------------------------------------------------------------------------------- /formal-version/nfv-mmtc-ctrl.py: -------------------------------------------------------------------------------- 1 | from ryu.base import app_manager 2 | from ryu.controller import ofp_event 3 | from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER 4 | from ryu.controller.handler import set_ev_cls 5 | from ryu.ofproto import ofproto_v1_3 6 | from ryu.lib.packet import packet 7 | from ryu.lib.packet import ethernet, ether_types, arp 8 | 9 | # REST Api Packages 10 | import json 11 | import logging 12 | from ryu.app.wsgi import WSGIApplication, ControllerBase, route 13 | from webob import Response 14 | 15 | ue_instance_name = 'NFV_mMTC' 16 | 17 | 18 | class NFVmmtcCtrl(app_manager.RyuApp): 19 | OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] 20 | _CONTEXTS = {'wsgi': WSGIApplication} 21 | 22 | def __init__(self, *args, **kwargs): 23 | super(NFVmmtcCtrl, self).__init__(*args, **kwargs) 24 | self.mac_to_port = {} # mac address to inbound port table 25 | self.arp_broadcast = {} # arp broadcast inbound port table 26 | wsgi = kwargs['wsgi'] 27 | wsgi.register(EastWestAPI, {ue_instance_name: self}) 28 | 29 | @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER) 30 | def switch_features_handler(self, ev): 31 | datapath = ev.msg.datapath 32 | ofproto = datapath.ofproto 33 | parser = datapath.ofproto_parser 34 | 35 | # install table-miss flow entry 36 | # 37 | # We specify NO BUFFER to max_len of the output action due to 38 | # OVS bug. At this moment, if we specify a lesser number, e.g., 39 | # 128, OVS will send Packet-In with invalid buffer_id and 40 | # truncated packet data. In that case, we cannot output packets 41 | # correctly. The bug has been fixed in OVS v2.1.0. 42 | match = parser.OFPMatch() 43 | actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, 44 | ofproto.OFPCML_NO_BUFFER)] 45 | self.add_flow(datapath, 0, match, actions) 46 | 47 | def add_flow(self, datapath, priority, match, actions, buffer_id=None): 48 | ofproto = datapath.ofproto 49 | parser = datapath.ofproto_parser 50 | 51 | inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, 52 | actions)] 53 | if buffer_id: 54 | mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id, 55 | priority=priority, match=match, 56 | instructions=inst) 57 | else: 58 | mod = parser.OFPFlowMod(datapath=datapath, priority=priority, 59 | match=match, instructions=inst) 60 | datapath.send_msg(mod) 61 | 62 | @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) 63 | def _packet_in_handler(self, ev): 64 | # If you hit this you might want to increase 65 | # the "miss_send_length" of your switch 66 | if ev.msg.msg_len < ev.msg.total_len: 67 | self.logger.debug("packet truncated: only %s of %s bytes", 68 | ev.msg.msg_len, ev.msg.total_len) 69 | msg = ev.msg 70 | datapath = msg.datapath 71 | ofproto = datapath.ofproto 72 | parser = datapath.ofproto_parser 73 | in_port = msg.match['in_port'] 74 | 75 | pkt = packet.Packet(msg.data) 76 | eth = pkt.get_protocols(ethernet.ethernet)[0] 77 | dst = eth.dst 78 | src = eth.src 79 | dpid = datapath.id 80 | 81 | # ignore lldp and ipv6 packet 82 | if eth.ethertype == ether_types.ETH_TYPE_LLDP or eth.ethertype == ether_types.ETH_TYPE_IPV6: 83 | return 84 | 85 | self.logger.info("Packet In: %s %s -> %s | port:%s", dpid, src, dst, in_port) 86 | 87 | if eth.ethertype == ether_types.ETH_TYPE_ARP and dst == "ff:ff:ff:ff:ff:ff": 88 | arp_dst_ip = pkt.get_protocol(arp.arp).dst_ip 89 | if (dpid, src, arp_dst_ip) in self.arp_broadcast: 90 | if self.arp_broadcast[(dpid, src, arp_dst_ip)] != in_port: 91 | out = datapath.ofproto_parser.OFPPacketOut( 92 | datapath=datapath, 93 | buffer_id=datapath.ofproto.OFP_NO_BUFFER, 94 | in_port=in_port, 95 | actions=[], data=None) 96 | datapath.send_msg(out) 97 | self.logger.info('ARP Loop Maker Dropped!') 98 | 99 | return 100 | else: # learn arp broadcast table 101 | self.arp_broadcast[(dpid, src, arp_dst_ip)] = in_port 102 | 103 | self.mac_to_port.setdefault(dpid, {}) 104 | # learn a mac address to avoid FLOOD next time. 105 | self.mac_to_port[dpid][src] = in_port 106 | 107 | if dst in self.mac_to_port[dpid]: 108 | out_port = self.mac_to_port[dpid][dst] 109 | else: 110 | out_port = ofproto.OFPP_FLOOD 111 | 112 | actions = [parser.OFPActionOutput(out_port)] 113 | 114 | # install a flow to avoid packet_in next time 115 | if out_port != ofproto.OFPP_FLOOD: 116 | match = parser.OFPMatch(in_port=in_port, eth_dst=dst, eth_src=src) 117 | # verify if we have a valid buffer_id, if yes avoid to send both 118 | # flow_mod & packet_out 119 | if msg.buffer_id != ofproto.OFP_NO_BUFFER: 120 | self.add_flow(datapath, 1, match, actions, msg.buffer_id) 121 | return 122 | else: 123 | self.add_flow(datapath, 1, match, actions) 124 | data = None 125 | if msg.buffer_id == ofproto.OFP_NO_BUFFER: 126 | data = msg.data 127 | 128 | out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id, 129 | in_port=in_port, actions=actions, data=data) 130 | datapath.send_msg(out) 131 | 132 | 133 | class EastWestAPI(ControllerBase): 134 | def __init__(self, req, link, data, **config): 135 | super(EastWestAPI, self).__init__(req, link, data, **config) 136 | self.mMTC_app = data[ue_instance_name] 137 | self.logger = logging.getLogger(self.__class__.__name__) 138 | self.authentication = { 139 | 'TEST': '033bd94b1168d7e4f0d644c3c95e35bf', 140 | 'URLLC': 'dfdc323ef40c8f38f5f022a5554f2dee', 141 | 'EMBB': 'e9406f9b456569f230a23d21464189f2', 142 | 'MMTC': '1d99331a7879c3c5b90998f8c3c6a9d6' 143 | } 144 | self.unauthenticated = Response( 145 | status=401, 146 | content_type='application/json', 147 | body=json.dumps( 148 | {'error': 'unauthenticated'}, 149 | indent=4 150 | ) + '\n' 151 | ) 152 | 153 | @route('mac-port-table', '/mac-port-table', methods=['GET']) 154 | def _mac_port_table(self, req, **kwargs): 155 | mMTC_app = self.mMTC_app 156 | body = json.dumps(mMTC_app.mac_to_port, indent=4) + '\n' 157 | 158 | if 'Authentication' in req.headers: 159 | if req.headers['Authentication'] in self.authentication.values(): 160 | return Response(content_type='application/json', body=body) 161 | else: 162 | return self.unauthenticated 163 | else: 164 | return self.unauthenticated 165 | 166 | @route('arp-table', '/arp-table', methods=['GET']) 167 | def _arp_table(self, req, **kwargs): 168 | arp_broadcast = self.mMTC_app.arp_broadcast 169 | arp_str_table = {} 170 | for key in arp_broadcast.keys(): 171 | arp_str_table[str(key)] = arp_broadcast[key] 172 | body = json.dumps(arp_str_table, indent=4) + '\n' 173 | 174 | if 'Authentication' in req.headers: 175 | if req.headers['Authentication'] in self.authentication.values(): 176 | return Response(content_type='application/json', body=body) 177 | else: 178 | return self.unauthenticated 179 | else: 180 | return self.unauthenticated 181 | -------------------------------------------------------------------------------- /formal-version/nfv-urllc-ctrl.py: -------------------------------------------------------------------------------- 1 | from ryu.base import app_manager 2 | from ryu.controller import ofp_event 3 | from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER 4 | from ryu.controller.handler import set_ev_cls 5 | from ryu.ofproto import ofproto_v1_3 6 | from ryu.lib.packet import packet 7 | from ryu.lib.packet import ethernet, ether_types, arp 8 | 9 | # REST Api Packages 10 | import json 11 | import logging 12 | from ryu.app.wsgi import WSGIApplication, ControllerBase, route 13 | from webob import Response 14 | 15 | ue_instance_name = 'NFV_URLLC' 16 | 17 | 18 | class NFVurllcCtrl(app_manager.RyuApp): 19 | OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] 20 | _CONTEXTS = {'wsgi': WSGIApplication} 21 | 22 | def __init__(self, *args, **kwargs): 23 | super(NFVurllcCtrl, self).__init__(*args, **kwargs) 24 | self.mac_to_port = {} # mac address to inbound port table 25 | self.arp_broadcast = {} # arp broadcast inbound port table 26 | wsgi = kwargs['wsgi'] 27 | wsgi.register(EastWestAPI, {ue_instance_name: self}) 28 | 29 | @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER) 30 | def switch_features_handler(self, ev): 31 | datapath = ev.msg.datapath 32 | ofproto = datapath.ofproto 33 | parser = datapath.ofproto_parser 34 | 35 | # install table-miss flow entry 36 | # 37 | # We specify NO BUFFER to max_len of the output action due to 38 | # OVS bug. At this moment, if we specify a lesser number, e.g., 39 | # 128, OVS will send Packet-In with invalid buffer_id and 40 | # truncated packet data. In that case, we cannot output packets 41 | # correctly. The bug has been fixed in OVS v2.1.0. 42 | match = parser.OFPMatch() 43 | actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, 44 | ofproto.OFPCML_NO_BUFFER)] 45 | self.add_flow(datapath, 0, match, actions) 46 | 47 | def add_flow(self, datapath, priority, match, actions, buffer_id=None): 48 | ofproto = datapath.ofproto 49 | parser = datapath.ofproto_parser 50 | 51 | inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, 52 | actions)] 53 | if buffer_id: 54 | mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id, 55 | priority=priority, match=match, 56 | instructions=inst) 57 | else: 58 | mod = parser.OFPFlowMod(datapath=datapath, priority=priority, 59 | match=match, instructions=inst) 60 | datapath.send_msg(mod) 61 | 62 | @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) 63 | def _packet_in_handler(self, ev): 64 | # If you hit this you might want to increase 65 | # the "miss_send_length" of your switch 66 | if ev.msg.msg_len < ev.msg.total_len: 67 | self.logger.debug("packet truncated: only %s of %s bytes", 68 | ev.msg.msg_len, ev.msg.total_len) 69 | msg = ev.msg 70 | datapath = msg.datapath 71 | ofproto = datapath.ofproto 72 | parser = datapath.ofproto_parser 73 | in_port = msg.match['in_port'] 74 | 75 | pkt = packet.Packet(msg.data) 76 | eth = pkt.get_protocols(ethernet.ethernet)[0] 77 | dst = eth.dst 78 | src = eth.src 79 | dpid = datapath.id 80 | 81 | # ignore lldp and ipv6 packet 82 | if eth.ethertype == ether_types.ETH_TYPE_LLDP or eth.ethertype == ether_types.ETH_TYPE_IPV6: 83 | return 84 | 85 | self.logger.info("Packet In: %s %s -> %s | port:%s", 86 | dpid, src, dst, in_port) 87 | 88 | if eth.ethertype == ether_types.ETH_TYPE_ARP and dst == "ff:ff:ff:ff:ff:ff": 89 | arp_dst_ip = pkt.get_protocol(arp.arp).dst_ip 90 | if (dpid, src, arp_dst_ip) in self.arp_broadcast: 91 | if self.arp_broadcast[(dpid, src, arp_dst_ip)] != in_port: 92 | out = datapath.ofproto_parser.OFPPacketOut( 93 | datapath=datapath, 94 | buffer_id=datapath.ofproto.OFP_NO_BUFFER, 95 | in_port=in_port, 96 | actions=[], data=None) 97 | datapath.send_msg(out) 98 | self.logger.info('ARP Loop Maker Dropped!') 99 | 100 | return 101 | else: # learn arp broadcast table 102 | self.arp_broadcast[(dpid, src, arp_dst_ip)] = in_port 103 | 104 | self.mac_to_port.setdefault(dpid, {}) 105 | # learn a mac address to avoid FLOOD next time. 106 | self.mac_to_port[dpid][src] = in_port 107 | 108 | if dst in self.mac_to_port[dpid]: 109 | out_port = self.mac_to_port[dpid][dst] 110 | else: 111 | out_port = ofproto.OFPP_FLOOD 112 | 113 | actions = [parser.OFPActionOutput(out_port)] 114 | 115 | # install a flow to avoid packet_in next time 116 | if out_port != ofproto.OFPP_FLOOD: 117 | match = parser.OFPMatch(in_port=in_port, eth_dst=dst, eth_src=src) 118 | # verify if we have a valid buffer_id, if yes avoid to send both 119 | # flow_mod & packet_out 120 | if msg.buffer_id != ofproto.OFP_NO_BUFFER: 121 | self.add_flow(datapath, 1, match, actions, msg.buffer_id) 122 | return 123 | else: 124 | self.add_flow(datapath, 1, match, actions) 125 | data = None 126 | if msg.buffer_id == ofproto.OFP_NO_BUFFER: 127 | data = msg.data 128 | 129 | out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id, 130 | in_port=in_port, actions=actions, data=data) 131 | datapath.send_msg(out) 132 | 133 | 134 | class EastWestAPI(ControllerBase): 135 | def __init__(self, req, link, data, **config): 136 | super(EastWestAPI, self).__init__(req, link, data, **config) 137 | self.URLLC_app = data[ue_instance_name] 138 | self.logger = logging.getLogger(self.__class__.__name__) 139 | self.authentication = { 140 | 'TEST': '033bd94b1168d7e4f0d644c3c95e35bf', 141 | 'URLLC': 'dfdc323ef40c8f38f5f022a5554f2dee', 142 | 'EMBB': 'e9406f9b456569f230a23d21464189f2', 143 | 'MMTC': '1d99331a7879c3c5b90998f8c3c6a9d6' 144 | } 145 | self.unauthenticated = Response( 146 | status=401, 147 | content_type='application/json', 148 | body=json.dumps( 149 | {'error': 'unauthenticated'}, 150 | indent=4 151 | ) + '\n' 152 | ) 153 | 154 | @route('mac-port-table', '/mac-port-table', methods=['GET']) 155 | def _mac_port_table(self, req, **kwargs): 156 | URLLC_app = self.URLLC_app 157 | body = json.dumps(URLLC_app.mac_to_port, indent=4) + '\n' 158 | 159 | if 'Authentication' in req.headers: 160 | if req.headers['Authentication'] in self.authentication.values(): 161 | return Response(content_type='application/json', body=body) 162 | else: 163 | return self.unauthenticated 164 | else: 165 | return self.unauthenticated 166 | 167 | @route('arp-table', '/arp-table', methods=['GET']) 168 | def _arp_table(self, req, **kwargs): 169 | arp_broadcast = self.URLLC_app.arp_broadcast 170 | arp_str_table = {} 171 | for key in arp_broadcast.keys(): 172 | arp_str_table[str(key)] = arp_broadcast[key] 173 | body = json.dumps(arp_str_table, indent=4) + '\n' 174 | 175 | if 'Authentication' in req.headers: 176 | if req.headers['Authentication'] in self.authentication.values(): 177 | return Response(content_type='application/json', body=body) 178 | else: 179 | return self.unauthenticated 180 | else: 181 | return self.unauthenticated 182 | -------------------------------------------------------------------------------- /formal-version/sba-af-ctrl.py: -------------------------------------------------------------------------------- 1 | from ryu.base import app_manager 2 | from ryu.controller import ofp_event 3 | from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER 4 | from ryu.controller.handler import set_ev_cls 5 | from ryu.ofproto import ofproto_v1_3 6 | from ryu.lib.packet import packet 7 | from ryu.lib.packet import ethernet, ether_types, arp 8 | 9 | # REST Api Packages 10 | import json 11 | import logging 12 | from ryu.app.wsgi import WSGIApplication, ControllerBase, route 13 | from webob import Response 14 | 15 | sba_instance_name = 'SBA_AF' 16 | 17 | 18 | class SBAafCtrl(app_manager.RyuApp): 19 | OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] 20 | _CONTEXTS = {'wsgi': WSGIApplication} 21 | 22 | def __init__(self, *args, **kwargs): 23 | super(SBAafCtrl, self).__init__(*args, **kwargs) 24 | self.mac_to_port = {} # mac address to inbound port table 25 | self.arp_broadcast = {} # arp broadcast inbound port table 26 | wsgi = kwargs['wsgi'] 27 | wsgi.register(EastWestAPI, {sba_instance_name: self}) 28 | 29 | @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER) 30 | def switch_features_handler(self, ev): 31 | datapath = ev.msg.datapath 32 | ofproto = datapath.ofproto 33 | parser = datapath.ofproto_parser 34 | 35 | # install table-miss flow entry 36 | # 37 | # We specify NO BUFFER to max_len of the output action due to 38 | # OVS bug. At this moment, if we specify a lesser number, e.g., 39 | # 128, OVS will send Packet-In with invalid buffer_id and 40 | # truncated packet data. In that case, we cannot output packets 41 | # correctly. The bug has been fixed in OVS v2.1.0. 42 | match = parser.OFPMatch() 43 | actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, 44 | ofproto.OFPCML_NO_BUFFER)] 45 | self.add_flow(datapath, 0, match, actions) 46 | 47 | def add_flow(self, datapath, priority, match, actions, buffer_id=None): 48 | ofproto = datapath.ofproto 49 | parser = datapath.ofproto_parser 50 | 51 | inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, 52 | actions)] 53 | if buffer_id: 54 | mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id, 55 | priority=priority, match=match, 56 | instructions=inst) 57 | else: 58 | mod = parser.OFPFlowMod(datapath=datapath, priority=priority, 59 | match=match, instructions=inst) 60 | datapath.send_msg(mod) 61 | 62 | @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) 63 | def _packet_in_handler(self, ev): 64 | # If you hit this you might want to increase 65 | # the "miss_send_length" of your switch 66 | if ev.msg.msg_len < ev.msg.total_len: 67 | self.logger.debug("packet truncated: only %s of %s bytes", 68 | ev.msg.msg_len, ev.msg.total_len) 69 | msg = ev.msg 70 | datapath = msg.datapath 71 | ofproto = datapath.ofproto 72 | parser = datapath.ofproto_parser 73 | in_port = msg.match['in_port'] 74 | 75 | pkt = packet.Packet(msg.data) 76 | eth = pkt.get_protocols(ethernet.ethernet)[0] 77 | dst = eth.dst 78 | src = eth.src 79 | dpid = datapath.id 80 | 81 | # ignore lldp and ipv6 packet 82 | if eth.ethertype == ether_types.ETH_TYPE_LLDP or eth.ethertype == ether_types.ETH_TYPE_IPV6: 83 | return 84 | 85 | self.logger.info("Packet In: %s %s -> %s | port:%s", 86 | dpid, src, dst, in_port) 87 | 88 | if eth.ethertype == ether_types.ETH_TYPE_ARP and dst == "ff:ff:ff:ff:ff:ff": 89 | arp_dst_ip = pkt.get_protocol(arp.arp).dst_ip 90 | if (dpid, src, arp_dst_ip) in self.arp_broadcast: 91 | if self.arp_broadcast[(dpid, src, arp_dst_ip)] != in_port: 92 | out = datapath.ofproto_parser.OFPPacketOut( 93 | datapath=datapath, 94 | buffer_id=datapath.ofproto.OFP_NO_BUFFER, 95 | in_port=in_port, 96 | actions=[], data=None) 97 | datapath.send_msg(out) 98 | self.logger.info('ARP Loop Maker Dropped!') 99 | 100 | return 101 | else: # learn arp broadcast table 102 | self.arp_broadcast[(dpid, src, arp_dst_ip)] = in_port 103 | 104 | self.mac_to_port.setdefault(dpid, {}) 105 | # learn a mac address to avoid FLOOD next time. 106 | self.mac_to_port[dpid][src] = in_port 107 | 108 | if dst in self.mac_to_port[dpid]: 109 | out_port = self.mac_to_port[dpid][dst] 110 | else: 111 | out_port = ofproto.OFPP_FLOOD 112 | 113 | actions = [parser.OFPActionOutput(out_port)] 114 | 115 | # install a flow to avoid packet_in next time 116 | if out_port != ofproto.OFPP_FLOOD: 117 | match = parser.OFPMatch(in_port=in_port, eth_dst=dst, eth_src=src) 118 | # verify if we have a valid buffer_id, if yes avoid to send both 119 | # flow_mod & packet_out 120 | if msg.buffer_id != ofproto.OFP_NO_BUFFER: 121 | self.add_flow(datapath, 1, match, actions, msg.buffer_id) 122 | return 123 | else: 124 | self.add_flow(datapath, 1, match, actions) 125 | data = None 126 | if msg.buffer_id == ofproto.OFP_NO_BUFFER: 127 | data = msg.data 128 | 129 | out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id, 130 | in_port=in_port, actions=actions, data=data) 131 | datapath.send_msg(out) 132 | 133 | 134 | class EastWestAPI(ControllerBase): 135 | def __init__(self, req, link, data, **config): 136 | super(EastWestAPI, self).__init__(req, link, data, **config) 137 | self.AF_app = data[sba_instance_name] 138 | self.logger = logging.getLogger(self.__class__.__name__) 139 | self.authentication = { 140 | 'TEST': '033bd94b1168d7e4f0d644c3c95e35bf', 141 | 'URLLC': 'dfdc323ef40c8f38f5f022a5554f2dee', 142 | 'EMBB': 'e9406f9b456569f230a23d21464189f2', 143 | 'MMTC': '1d99331a7879c3c5b90998f8c3c6a9d6' 144 | } 145 | self.unauthenticated = Response( 146 | status=401, 147 | content_type='application/json', 148 | body=json.dumps( 149 | {'error': 'unauthenticated'}, 150 | indent=4 151 | ) + '\n' 152 | ) 153 | 154 | @route('mac-port-table', '/mac-port-table', methods=['GET']) 155 | def _mac_port_table(self, req, **kwargs): 156 | AF_app = self.AF_app 157 | body = json.dumps(AF_app.mac_to_port, indent=4) + '\n' 158 | 159 | if 'Authentication' in req.headers: 160 | if req.headers['Authentication'] in self.authentication.values(): 161 | return Response(content_type='application/json', body=body) 162 | else: 163 | return self.unauthenticated 164 | else: 165 | return self.unauthenticated 166 | 167 | @route('arp-table', '/arp-table', methods=['GET']) 168 | def _arp_table(self, req, **kwargs): 169 | arp_broadcast = self.AF_app.arp_broadcast 170 | arp_str_table = {} 171 | for key in arp_broadcast.keys(): 172 | arp_str_table[str(key)] = arp_broadcast[key] 173 | body = json.dumps(arp_str_table, indent=4) + '\n' 174 | 175 | if 'Authentication' in req.headers: 176 | if req.headers['Authentication'] in self.authentication.values(): 177 | return Response(content_type='application/json', body=body) 178 | else: 179 | return self.unauthenticated 180 | else: 181 | return self.unauthenticated 182 | -------------------------------------------------------------------------------- /formal-version/sba-amf-ctrl.py: -------------------------------------------------------------------------------- 1 | from ryu.base import app_manager 2 | from ryu.controller import ofp_event 3 | from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER 4 | from ryu.controller.handler import set_ev_cls 5 | from ryu.ofproto import ofproto_v1_3 6 | from ryu.lib.packet import packet 7 | from ryu.lib.packet import ethernet, ether_types, arp 8 | 9 | # REST Api Packages 10 | import json 11 | import logging 12 | from ryu.app.wsgi import WSGIApplication, ControllerBase, route 13 | from webob import Response 14 | 15 | sba_instance_name = 'SBA_AMF' 16 | 17 | 18 | class SBAamfCtrl(app_manager.RyuApp): 19 | OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] 20 | _CONTEXTS = {'wsgi': WSGIApplication} 21 | 22 | def __init__(self, *args, **kwargs): 23 | super(SBAamfCtrl, self).__init__(*args, **kwargs) 24 | self.mac_to_port = {} # mac address to inbound port table 25 | self.arp_broadcast = {} # arp broadcast inbound port table 26 | wsgi = kwargs['wsgi'] 27 | wsgi.register(EastWestAPI, {sba_instance_name: self}) 28 | 29 | @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER) 30 | def switch_features_handler(self, ev): 31 | datapath = ev.msg.datapath 32 | ofproto = datapath.ofproto 33 | parser = datapath.ofproto_parser 34 | 35 | # install table-miss flow entry 36 | # 37 | # We specify NO BUFFER to max_len of the output action due to 38 | # OVS bug. At this moment, if we specify a lesser number, e.g., 39 | # 128, OVS will send Packet-In with invalid buffer_id and 40 | # truncated packet data. In that case, we cannot output packets 41 | # correctly. The bug has been fixed in OVS v2.1.0. 42 | match = parser.OFPMatch() 43 | actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, 44 | ofproto.OFPCML_NO_BUFFER)] 45 | self.add_flow(datapath, 0, match, actions) 46 | 47 | def add_flow(self, datapath, priority, match, actions, buffer_id=None): 48 | ofproto = datapath.ofproto 49 | parser = datapath.ofproto_parser 50 | 51 | inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, 52 | actions)] 53 | if buffer_id: 54 | mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id, 55 | priority=priority, match=match, 56 | instructions=inst) 57 | else: 58 | mod = parser.OFPFlowMod(datapath=datapath, priority=priority, 59 | match=match, instructions=inst) 60 | datapath.send_msg(mod) 61 | 62 | @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) 63 | def _packet_in_handler(self, ev): 64 | # If you hit this you might want to increase 65 | # the "miss_send_length" of your switch 66 | if ev.msg.msg_len < ev.msg.total_len: 67 | self.logger.debug("packet truncated: only %s of %s bytes", 68 | ev.msg.msg_len, ev.msg.total_len) 69 | msg = ev.msg 70 | datapath = msg.datapath 71 | ofproto = datapath.ofproto 72 | parser = datapath.ofproto_parser 73 | in_port = msg.match['in_port'] 74 | 75 | pkt = packet.Packet(msg.data) 76 | eth = pkt.get_protocols(ethernet.ethernet)[0] 77 | dst = eth.dst 78 | src = eth.src 79 | dpid = datapath.id 80 | 81 | # ignore lldp and ipv6 packet 82 | if eth.ethertype == ether_types.ETH_TYPE_LLDP or eth.ethertype == ether_types.ETH_TYPE_IPV6: 83 | return 84 | 85 | self.logger.info("Packet In: %s %s -> %s | port:%s", 86 | dpid, src, dst, in_port) 87 | 88 | if eth.ethertype == ether_types.ETH_TYPE_ARP and dst == "ff:ff:ff:ff:ff:ff": 89 | arp_dst_ip = pkt.get_protocol(arp.arp).dst_ip 90 | if (dpid, src, arp_dst_ip) in self.arp_broadcast: 91 | if self.arp_broadcast[(dpid, src, arp_dst_ip)] != in_port: 92 | out = datapath.ofproto_parser.OFPPacketOut( 93 | datapath=datapath, 94 | buffer_id=datapath.ofproto.OFP_NO_BUFFER, 95 | in_port=in_port, 96 | actions=[], data=None) 97 | datapath.send_msg(out) 98 | self.logger.info('ARP Loop Maker Dropped!') 99 | 100 | return 101 | else: # learn arp broadcast table 102 | self.arp_broadcast[(dpid, src, arp_dst_ip)] = in_port 103 | 104 | self.mac_to_port.setdefault(dpid, {}) 105 | # learn a mac address to avoid FLOOD next time. 106 | self.mac_to_port[dpid][src] = in_port 107 | 108 | if dst in self.mac_to_port[dpid]: 109 | out_port = self.mac_to_port[dpid][dst] 110 | else: 111 | out_port = ofproto.OFPP_FLOOD 112 | 113 | actions = [parser.OFPActionOutput(out_port)] 114 | 115 | # install a flow to avoid packet_in next time 116 | if out_port != ofproto.OFPP_FLOOD: 117 | match = parser.OFPMatch(in_port=in_port, eth_dst=dst, eth_src=src) 118 | # verify if we have a valid buffer_id, if yes avoid to send both 119 | # flow_mod & packet_out 120 | if msg.buffer_id != ofproto.OFP_NO_BUFFER: 121 | self.add_flow(datapath, 1, match, actions, msg.buffer_id) 122 | return 123 | else: 124 | self.add_flow(datapath, 1, match, actions) 125 | data = None 126 | if msg.buffer_id == ofproto.OFP_NO_BUFFER: 127 | data = msg.data 128 | 129 | out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id, 130 | in_port=in_port, actions=actions, data=data) 131 | datapath.send_msg(out) 132 | 133 | 134 | class EastWestAPI(ControllerBase): 135 | def __init__(self, req, link, data, **config): 136 | super(EastWestAPI, self).__init__(req, link, data, **config) 137 | self.AMF_app = data[sba_instance_name] 138 | self.logger = logging.getLogger(self.__class__.__name__) 139 | self.authentication = { 140 | 'TEST': '033bd94b1168d7e4f0d644c3c95e35bf', 141 | 'URLLC': 'dfdc323ef40c8f38f5f022a5554f2dee', 142 | 'EMBB': 'e9406f9b456569f230a23d21464189f2', 143 | 'MMTC': '1d99331a7879c3c5b90998f8c3c6a9d6' 144 | } 145 | self.unauthenticated = Response( 146 | status=401, 147 | content_type='application/json', 148 | body=json.dumps( 149 | {'error': 'unauthenticated'}, 150 | indent=4 151 | ) + '\n' 152 | ) 153 | 154 | @route('mac-port-table', '/mac-port-table', methods=['GET']) 155 | def _mac_port_table(self, req, **kwargs): 156 | AMF_app = self.AMF_app 157 | body = json.dumps(AMF_app.mac_to_port, indent=4) + '\n' 158 | 159 | if 'Authentication' in req.headers: 160 | if req.headers['Authentication'] in self.authentication.values(): 161 | return Response(content_type='application/json', body=body) 162 | else: 163 | return self.unauthenticated 164 | else: 165 | return self.unauthenticated 166 | 167 | @route('arp-table', '/arp-table', methods=['GET']) 168 | def _arp_table(self, req, **kwargs): 169 | arp_broadcast = self.AMF_app.arp_broadcast 170 | arp_str_table = {} 171 | for key in arp_broadcast.keys(): 172 | arp_str_table[str(key)] = arp_broadcast[key] 173 | body = json.dumps(arp_str_table, indent=4) + '\n' 174 | 175 | if 'Authentication' in req.headers: 176 | if req.headers['Authentication'] in self.authentication.values(): 177 | return Response(content_type='application/json', body=body) 178 | else: 179 | return self.unauthenticated 180 | else: 181 | return self.unauthenticated 182 | -------------------------------------------------------------------------------- /formal-version/sba-ausf-ctrl.py: -------------------------------------------------------------------------------- 1 | from ryu.base import app_manager 2 | from ryu.controller import ofp_event 3 | from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER 4 | from ryu.controller.handler import set_ev_cls 5 | from ryu.ofproto import ofproto_v1_3 6 | from ryu.lib.packet import packet 7 | from ryu.lib.packet import ethernet, ether_types, arp 8 | 9 | # REST Api Packages 10 | import json 11 | import logging 12 | from ryu.app.wsgi import WSGIApplication, ControllerBase, route 13 | from webob import Response 14 | 15 | sba_instance_name = 'SBA_AUSF' 16 | 17 | 18 | class SBAausfCtrl(app_manager.RyuApp): 19 | OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] 20 | _CONTEXTS = {'wsgi': WSGIApplication} 21 | 22 | def __init__(self, *args, **kwargs): 23 | super(SBAausfCtrl, self).__init__(*args, **kwargs) 24 | self.mac_to_port = {} # mac address to inbound port table 25 | self.arp_broadcast = {} # arp broadcast inbound port table 26 | wsgi = kwargs['wsgi'] 27 | wsgi.register(EastWestAPI, {sba_instance_name: self}) 28 | 29 | @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER) 30 | def switch_features_handler(self, ev): 31 | datapath = ev.msg.datapath 32 | ofproto = datapath.ofproto 33 | parser = datapath.ofproto_parser 34 | 35 | # install table-miss flow entry 36 | # 37 | # We specify NO BUFFER to max_len of the output action due to 38 | # OVS bug. At this moment, if we specify a lesser number, e.g., 39 | # 128, OVS will send Packet-In with invalid buffer_id and 40 | # truncated packet data. In that case, we cannot output packets 41 | # correctly. The bug has been fixed in OVS v2.1.0. 42 | match = parser.OFPMatch() 43 | actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, 44 | ofproto.OFPCML_NO_BUFFER)] 45 | self.add_flow(datapath, 0, match, actions) 46 | 47 | def add_flow(self, datapath, priority, match, actions, buffer_id=None): 48 | ofproto = datapath.ofproto 49 | parser = datapath.ofproto_parser 50 | 51 | inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, 52 | actions)] 53 | if buffer_id: 54 | mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id, 55 | priority=priority, match=match, 56 | instructions=inst) 57 | else: 58 | mod = parser.OFPFlowMod(datapath=datapath, priority=priority, 59 | match=match, instructions=inst) 60 | datapath.send_msg(mod) 61 | 62 | @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) 63 | def _packet_in_handler(self, ev): 64 | # If you hit this you might want to increase 65 | # the "miss_send_length" of your switch 66 | if ev.msg.msg_len < ev.msg.total_len: 67 | self.logger.debug("packet truncated: only %s of %s bytes", 68 | ev.msg.msg_len, ev.msg.total_len) 69 | msg = ev.msg 70 | datapath = msg.datapath 71 | ofproto = datapath.ofproto 72 | parser = datapath.ofproto_parser 73 | in_port = msg.match['in_port'] 74 | 75 | pkt = packet.Packet(msg.data) 76 | eth = pkt.get_protocols(ethernet.ethernet)[0] 77 | dst = eth.dst 78 | src = eth.src 79 | dpid = datapath.id 80 | 81 | # ignore lldp and ipv6 packet 82 | if eth.ethertype == ether_types.ETH_TYPE_LLDP or eth.ethertype == ether_types.ETH_TYPE_IPV6: 83 | return 84 | 85 | self.logger.info("Packet In: %s %s -> %s | port:%s", 86 | dpid, src, dst, in_port) 87 | 88 | if eth.ethertype == ether_types.ETH_TYPE_ARP and dst == "ff:ff:ff:ff:ff:ff": 89 | arp_dst_ip = pkt.get_protocol(arp.arp).dst_ip 90 | if (dpid, src, arp_dst_ip) in self.arp_broadcast: 91 | if self.arp_broadcast[(dpid, src, arp_dst_ip)] != in_port: 92 | out = datapath.ofproto_parser.OFPPacketOut( 93 | datapath=datapath, 94 | buffer_id=datapath.ofproto.OFP_NO_BUFFER, 95 | in_port=in_port, 96 | actions=[], data=None) 97 | datapath.send_msg(out) 98 | self.logger.info('ARP Loop Maker Dropped!') 99 | 100 | return 101 | else: # learn arp broadcast table 102 | self.arp_broadcast[(dpid, src, arp_dst_ip)] = in_port 103 | 104 | self.mac_to_port.setdefault(dpid, {}) 105 | # learn a mac address to avoid FLOOD next time. 106 | self.mac_to_port[dpid][src] = in_port 107 | 108 | if dst in self.mac_to_port[dpid]: 109 | out_port = self.mac_to_port[dpid][dst] 110 | else: 111 | out_port = ofproto.OFPP_FLOOD 112 | 113 | actions = [parser.OFPActionOutput(out_port)] 114 | 115 | # install a flow to avoid packet_in next time 116 | if out_port != ofproto.OFPP_FLOOD: 117 | match = parser.OFPMatch(in_port=in_port, eth_dst=dst, eth_src=src) 118 | # verify if we have a valid buffer_id, if yes avoid to send both 119 | # flow_mod & packet_out 120 | if msg.buffer_id != ofproto.OFP_NO_BUFFER: 121 | self.add_flow(datapath, 1, match, actions, msg.buffer_id) 122 | return 123 | else: 124 | self.add_flow(datapath, 1, match, actions) 125 | data = None 126 | if msg.buffer_id == ofproto.OFP_NO_BUFFER: 127 | data = msg.data 128 | 129 | out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id, 130 | in_port=in_port, actions=actions, data=data) 131 | datapath.send_msg(out) 132 | 133 | 134 | class EastWestAPI(ControllerBase): 135 | def __init__(self, req, link, data, **config): 136 | super(EastWestAPI, self).__init__(req, link, data, **config) 137 | self.AUSF_app = data[sba_instance_name] 138 | self.logger = logging.getLogger(self.__class__.__name__) 139 | self.authentication = { 140 | 'TEST': '033bd94b1168d7e4f0d644c3c95e35bf', 141 | 'URLLC': 'dfdc323ef40c8f38f5f022a5554f2dee', 142 | 'EMBB': 'e9406f9b456569f230a23d21464189f2', 143 | 'MMTC': '1d99331a7879c3c5b90998f8c3c6a9d6' 144 | } 145 | self.unauthenticated = Response( 146 | status=401, 147 | content_type='application/json', 148 | body=json.dumps( 149 | {'error': 'unauthenticated'}, 150 | indent=4 151 | ) + '\n' 152 | ) 153 | 154 | @route('mac-port-table', '/mac-port-table', methods=['GET']) 155 | def _mac_port_table(self, req, **kwargs): 156 | AUSF_app = self.AUSF_app 157 | body = json.dumps(AUSF_app.mac_to_port, indent=4) + '\n' 158 | 159 | if 'Authentication' in req.headers: 160 | if req.headers['Authentication'] in self.authentication.values(): 161 | return Response(content_type='application/json', body=body) 162 | else: 163 | return self.unauthenticated 164 | else: 165 | return self.unauthenticated 166 | 167 | @route('arp-table', '/arp-table', methods=['GET']) 168 | def _arp_table(self, req, **kwargs): 169 | arp_broadcast = self.AUSF_app.arp_broadcast 170 | arp_str_table = {} 171 | for key in arp_broadcast.keys(): 172 | arp_str_table[str(key)] = arp_broadcast[key] 173 | body = json.dumps(arp_str_table, indent=4) + '\n' 174 | 175 | if 'Authentication' in req.headers: 176 | if req.headers['Authentication'] in self.authentication.values(): 177 | return Response(content_type='application/json', body=body) 178 | else: 179 | return self.unauthenticated 180 | else: 181 | return self.unauthenticated 182 | -------------------------------------------------------------------------------- /formal-version/sba-nrf-ctrl.py: -------------------------------------------------------------------------------- 1 | from ryu.base import app_manager 2 | from ryu.controller import ofp_event 3 | from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER 4 | from ryu.controller.handler import set_ev_cls 5 | from ryu.ofproto import ofproto_v1_3 6 | from ryu.lib.packet import packet 7 | from ryu.lib.packet import ethernet, ether_types, arp 8 | 9 | # REST Api Packages 10 | import json 11 | import logging 12 | from ryu.app.wsgi import WSGIApplication, ControllerBase, route 13 | from webob import Response 14 | 15 | sba_instance_name = 'SBA_NRF' 16 | 17 | 18 | class SBAnrfCtrl(app_manager.RyuApp): 19 | OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] 20 | _CONTEXTS = {'wsgi': WSGIApplication} 21 | 22 | def __init__(self, *args, **kwargs): 23 | super(SBAnrfCtrl, self).__init__(*args, **kwargs) 24 | self.mac_to_port = {} # mac address to inbound port table 25 | self.arp_broadcast = {} # arp broadcast inbound port table 26 | wsgi = kwargs['wsgi'] 27 | wsgi.register(EastWestAPI, {sba_instance_name: self}) 28 | 29 | @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER) 30 | def switch_features_handler(self, ev): 31 | datapath = ev.msg.datapath 32 | ofproto = datapath.ofproto 33 | parser = datapath.ofproto_parser 34 | 35 | # install table-miss flow entry 36 | # 37 | # We specify NO BUFFER to max_len of the output action due to 38 | # OVS bug. At this moment, if we specify a lesser number, e.g., 39 | # 128, OVS will send Packet-In with invalid buffer_id and 40 | # truncated packet data. In that case, we cannot output packets 41 | # correctly. The bug has been fixed in OVS v2.1.0. 42 | match = parser.OFPMatch() 43 | actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, 44 | ofproto.OFPCML_NO_BUFFER)] 45 | self.add_flow(datapath, 0, match, actions) 46 | 47 | def add_flow(self, datapath, priority, match, actions, buffer_id=None): 48 | ofproto = datapath.ofproto 49 | parser = datapath.ofproto_parser 50 | 51 | inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, 52 | actions)] 53 | if buffer_id: 54 | mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id, 55 | priority=priority, match=match, 56 | instructions=inst) 57 | else: 58 | mod = parser.OFPFlowMod(datapath=datapath, priority=priority, 59 | match=match, instructions=inst) 60 | datapath.send_msg(mod) 61 | 62 | @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) 63 | def _packet_in_handler(self, ev): 64 | # If you hit this you might want to increase 65 | # the "miss_send_length" of your switch 66 | if ev.msg.msg_len < ev.msg.total_len: 67 | self.logger.debug("packet truncated: only %s of %s bytes", 68 | ev.msg.msg_len, ev.msg.total_len) 69 | msg = ev.msg 70 | datapath = msg.datapath 71 | ofproto = datapath.ofproto 72 | parser = datapath.ofproto_parser 73 | in_port = msg.match['in_port'] 74 | 75 | pkt = packet.Packet(msg.data) 76 | eth = pkt.get_protocols(ethernet.ethernet)[0] 77 | dst = eth.dst 78 | src = eth.src 79 | dpid = datapath.id 80 | 81 | # ignore lldp and ipv6 packet 82 | if eth.ethertype == ether_types.ETH_TYPE_LLDP or eth.ethertype == ether_types.ETH_TYPE_IPV6: 83 | return 84 | 85 | self.logger.info("Packet In: %s %s -> %s | port:%s", 86 | dpid, src, dst, in_port) 87 | 88 | if eth.ethertype == ether_types.ETH_TYPE_ARP and dst == "ff:ff:ff:ff:ff:ff": 89 | arp_dst_ip = pkt.get_protocol(arp.arp).dst_ip 90 | if (dpid, src, arp_dst_ip) in self.arp_broadcast: 91 | if self.arp_broadcast[(dpid, src, arp_dst_ip)] != in_port: 92 | out = datapath.ofproto_parser.OFPPacketOut( 93 | datapath=datapath, 94 | buffer_id=datapath.ofproto.OFP_NO_BUFFER, 95 | in_port=in_port, 96 | actions=[], data=None) 97 | datapath.send_msg(out) 98 | self.logger.info('ARP Loop Maker Dropped!') 99 | 100 | return 101 | else: # learn arp broadcast table 102 | self.arp_broadcast[(dpid, src, arp_dst_ip)] = in_port 103 | 104 | self.mac_to_port.setdefault(dpid, {}) 105 | # learn a mac address to avoid FLOOD next time. 106 | self.mac_to_port[dpid][src] = in_port 107 | 108 | if dst in self.mac_to_port[dpid]: 109 | out_port = self.mac_to_port[dpid][dst] 110 | else: 111 | out_port = ofproto.OFPP_FLOOD 112 | 113 | actions = [parser.OFPActionOutput(out_port)] 114 | 115 | # install a flow to avoid packet_in next time 116 | if out_port != ofproto.OFPP_FLOOD: 117 | match = parser.OFPMatch(in_port=in_port, eth_dst=dst, eth_src=src) 118 | # verify if we have a valid buffer_id, if yes avoid to send both 119 | # flow_mod & packet_out 120 | if msg.buffer_id != ofproto.OFP_NO_BUFFER: 121 | self.add_flow(datapath, 1, match, actions, msg.buffer_id) 122 | return 123 | else: 124 | self.add_flow(datapath, 1, match, actions) 125 | data = None 126 | if msg.buffer_id == ofproto.OFP_NO_BUFFER: 127 | data = msg.data 128 | 129 | out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id, 130 | in_port=in_port, actions=actions, data=data) 131 | datapath.send_msg(out) 132 | 133 | 134 | class EastWestAPI(ControllerBase): 135 | def __init__(self, req, link, data, **config): 136 | super(EastWestAPI, self).__init__(req, link, data, **config) 137 | self.NRF_app = data[sba_instance_name] 138 | self.logger = logging.getLogger(self.__class__.__name__) 139 | self.authentication = { 140 | 'TEST': '033bd94b1168d7e4f0d644c3c95e35bf', 141 | 'URLLC': 'dfdc323ef40c8f38f5f022a5554f2dee', 142 | 'EMBB': 'e9406f9b456569f230a23d21464189f2', 143 | 'MMTC': '1d99331a7879c3c5b90998f8c3c6a9d6' 144 | } 145 | self.unauthenticated = Response( 146 | status=401, 147 | content_type='application/json', 148 | body=json.dumps( 149 | {'error': 'unauthenticated'}, 150 | indent=4 151 | ) + '\n' 152 | ) 153 | 154 | @route('mac-port-table', '/mac-port-table', methods=['GET']) 155 | def _mac_port_table(self, req, **kwargs): 156 | NRF_app = self.NRF_app 157 | body = json.dumps(NRF_app.mac_to_port, indent=4) + '\n' 158 | 159 | if 'Authentication' in req.headers: 160 | if req.headers['Authentication'] in self.authentication.values(): 161 | return Response(content_type='application/json', body=body) 162 | else: 163 | return self.unauthenticated 164 | else: 165 | return self.unauthenticated 166 | 167 | @route('arp-table', '/arp-table', methods=['GET']) 168 | def _arp_table(self, req, **kwargs): 169 | arp_broadcast = self.NRF_app.arp_broadcast 170 | arp_str_table = {} 171 | for key in arp_broadcast.keys(): 172 | arp_str_table[str(key)] = arp_broadcast[key] 173 | body = json.dumps(arp_str_table, indent=4) + '\n' 174 | 175 | if 'Authentication' in req.headers: 176 | if req.headers['Authentication'] in self.authentication.values(): 177 | return Response(content_type='application/json', body=body) 178 | else: 179 | return self.unauthenticated 180 | else: 181 | return self.unauthenticated 182 | -------------------------------------------------------------------------------- /formal-version/sba-pcf-ctrl.py: -------------------------------------------------------------------------------- 1 | from ryu.base import app_manager 2 | from ryu.controller import ofp_event 3 | from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER 4 | from ryu.controller.handler import set_ev_cls 5 | from ryu.ofproto import ofproto_v1_3 6 | from ryu.lib.packet import packet 7 | from ryu.lib.packet import ethernet, ether_types, arp 8 | 9 | # REST Api Packages 10 | import json 11 | import logging 12 | from ryu.app.wsgi import WSGIApplication, ControllerBase, route 13 | from webob import Response 14 | 15 | sba_instance_name = 'SBA_PCF' 16 | 17 | 18 | class SBApcfCtrl(app_manager.RyuApp): 19 | OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] 20 | _CONTEXTS = {'wsgi': WSGIApplication} 21 | 22 | def __init__(self, *args, **kwargs): 23 | super(SBApcfCtrl, self).__init__(*args, **kwargs) 24 | self.mac_to_port = {} # mac address to inbound port table 25 | self.arp_broadcast = {} # arp broadcast inbound port table 26 | wsgi = kwargs['wsgi'] 27 | wsgi.register(EastWestAPI, {sba_instance_name: self}) 28 | 29 | @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER) 30 | def switch_features_handler(self, ev): 31 | datapath = ev.msg.datapath 32 | ofproto = datapath.ofproto 33 | parser = datapath.ofproto_parser 34 | 35 | # install table-miss flow entry 36 | # 37 | # We specify NO BUFFER to max_len of the output action due to 38 | # OVS bug. At this moment, if we specify a lesser number, e.g., 39 | # 128, OVS will send Packet-In with invalid buffer_id and 40 | # truncated packet data. In that case, we cannot output packets 41 | # correctly. The bug has been fixed in OVS v2.1.0. 42 | match = parser.OFPMatch() 43 | actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, 44 | ofproto.OFPCML_NO_BUFFER)] 45 | self.add_flow(datapath, 0, match, actions) 46 | 47 | def add_flow(self, datapath, priority, match, actions, buffer_id=None): 48 | ofproto = datapath.ofproto 49 | parser = datapath.ofproto_parser 50 | 51 | inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, 52 | actions)] 53 | if buffer_id: 54 | mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id, 55 | priority=priority, match=match, 56 | instructions=inst) 57 | else: 58 | mod = parser.OFPFlowMod(datapath=datapath, priority=priority, 59 | match=match, instructions=inst) 60 | datapath.send_msg(mod) 61 | 62 | @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) 63 | def _packet_in_handler(self, ev): 64 | # If you hit this you might want to increase 65 | # the "miss_send_length" of your switch 66 | if ev.msg.msg_len < ev.msg.total_len: 67 | self.logger.debug("packet truncated: only %s of %s bytes", 68 | ev.msg.msg_len, ev.msg.total_len) 69 | msg = ev.msg 70 | datapath = msg.datapath 71 | ofproto = datapath.ofproto 72 | parser = datapath.ofproto_parser 73 | in_port = msg.match['in_port'] 74 | 75 | pkt = packet.Packet(msg.data) 76 | eth = pkt.get_protocols(ethernet.ethernet)[0] 77 | dst = eth.dst 78 | src = eth.src 79 | dpid = datapath.id 80 | 81 | # ignore lldp and ipv6 packet 82 | if eth.ethertype == ether_types.ETH_TYPE_LLDP or eth.ethertype == ether_types.ETH_TYPE_IPV6: 83 | return 84 | 85 | self.logger.info("Packet In: %s %s -> %s | port:%s", 86 | dpid, src, dst, in_port) 87 | 88 | if eth.ethertype == ether_types.ETH_TYPE_ARP and dst == "ff:ff:ff:ff:ff:ff": 89 | arp_dst_ip = pkt.get_protocol(arp.arp).dst_ip 90 | if (dpid, src, arp_dst_ip) in self.arp_broadcast: 91 | if self.arp_broadcast[(dpid, src, arp_dst_ip)] != in_port: 92 | out = datapath.ofproto_parser.OFPPacketOut( 93 | datapath=datapath, 94 | buffer_id=datapath.ofproto.OFP_NO_BUFFER, 95 | in_port=in_port, 96 | actions=[], data=None) 97 | datapath.send_msg(out) 98 | self.logger.info('ARP Loop Maker Dropped!') 99 | 100 | return 101 | else: # learn arp broadcast table 102 | self.arp_broadcast[(dpid, src, arp_dst_ip)] = in_port 103 | 104 | self.mac_to_port.setdefault(dpid, {}) 105 | # learn a mac address to avoid FLOOD next time. 106 | self.mac_to_port[dpid][src] = in_port 107 | 108 | if dst in self.mac_to_port[dpid]: 109 | out_port = self.mac_to_port[dpid][dst] 110 | else: 111 | out_port = ofproto.OFPP_FLOOD 112 | 113 | actions = [parser.OFPActionOutput(out_port)] 114 | 115 | # install a flow to avoid packet_in next time 116 | if out_port != ofproto.OFPP_FLOOD: 117 | match = parser.OFPMatch(in_port=in_port, eth_dst=dst, eth_src=src) 118 | # verify if we have a valid buffer_id, if yes avoid to send both 119 | # flow_mod & packet_out 120 | if msg.buffer_id != ofproto.OFP_NO_BUFFER: 121 | self.add_flow(datapath, 1, match, actions, msg.buffer_id) 122 | return 123 | else: 124 | self.add_flow(datapath, 1, match, actions) 125 | data = None 126 | if msg.buffer_id == ofproto.OFP_NO_BUFFER: 127 | data = msg.data 128 | 129 | out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id, 130 | in_port=in_port, actions=actions, data=data) 131 | datapath.send_msg(out) 132 | 133 | 134 | class EastWestAPI(ControllerBase): 135 | def __init__(self, req, link, data, **config): 136 | super(EastWestAPI, self).__init__(req, link, data, **config) 137 | self.PCF_app = data[sba_instance_name] 138 | self.logger = logging.getLogger(self.__class__.__name__) 139 | self.authentication = { 140 | 'TEST': '033bd94b1168d7e4f0d644c3c95e35bf', 141 | 'URLLC': 'dfdc323ef40c8f38f5f022a5554f2dee', 142 | 'EMBB': 'e9406f9b456569f230a23d21464189f2', 143 | 'MMTC': '1d99331a7879c3c5b90998f8c3c6a9d6' 144 | } 145 | self.unauthenticated = Response( 146 | status=401, 147 | content_type='application/json', 148 | body=json.dumps( 149 | {'error': 'unauthenticated'}, 150 | indent=4 151 | ) + '\n' 152 | ) 153 | 154 | @route('mac-port-table', '/mac-port-table', methods=['GET']) 155 | def _mac_port_table(self, req, **kwargs): 156 | PCF_app = self.PCF_app 157 | body = json.dumps(PCF_app.mac_to_port, indent=4) + '\n' 158 | 159 | if 'Authentication' in req.headers: 160 | if req.headers['Authentication'] in self.authentication.values(): 161 | return Response(content_type='application/json', body=body) 162 | else: 163 | return self.unauthenticated 164 | else: 165 | return self.unauthenticated 166 | 167 | @route('arp-table', '/arp-table', methods=['GET']) 168 | def _arp_table(self, req, **kwargs): 169 | arp_broadcast = self.PCF_app.arp_broadcast 170 | arp_str_table = {} 171 | for key in arp_broadcast.keys(): 172 | arp_str_table[str(key)] = arp_broadcast[key] 173 | body = json.dumps(arp_str_table, indent=4) + '\n' 174 | 175 | if 'Authentication' in req.headers: 176 | if req.headers['Authentication'] in self.authentication.values(): 177 | return Response(content_type='application/json', body=body) 178 | else: 179 | return self.unauthenticated 180 | else: 181 | return self.unauthenticated 182 | -------------------------------------------------------------------------------- /formal-version/sba-smf-ctrl.py: -------------------------------------------------------------------------------- 1 | from ryu.base import app_manager 2 | from ryu.controller import ofp_event 3 | from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER 4 | from ryu.controller.handler import set_ev_cls 5 | from ryu.ofproto import ofproto_v1_3 6 | from ryu.lib.packet import packet 7 | from ryu.lib.packet import ethernet, ether_types, arp 8 | 9 | # REST Api Packages 10 | import json 11 | import logging 12 | from ryu.app.wsgi import WSGIApplication, ControllerBase, route 13 | from webob import Response 14 | 15 | sba_instance_name = 'SBA_SMF' 16 | 17 | 18 | class SBAsmfCtrl(app_manager.RyuApp): 19 | OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] 20 | _CONTEXTS = {'wsgi': WSGIApplication} 21 | 22 | def __init__(self, *args, **kwargs): 23 | super(SBAsmfCtrl, self).__init__(*args, **kwargs) 24 | self.mac_to_port = {} # mac address to inbound port table 25 | self.arp_broadcast = {} # arp broadcast inbound port table 26 | wsgi = kwargs['wsgi'] 27 | wsgi.register(EastWestAPI, {sba_instance_name: self}) 28 | 29 | @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER) 30 | def switch_features_handler(self, ev): 31 | datapath = ev.msg.datapath 32 | ofproto = datapath.ofproto 33 | parser = datapath.ofproto_parser 34 | 35 | # install table-miss flow entry 36 | # 37 | # We specify NO BUFFER to max_len of the output action due to 38 | # OVS bug. At this moment, if we specify a lesser number, e.g., 39 | # 128, OVS will send Packet-In with invalid buffer_id and 40 | # truncated packet data. In that case, we cannot output packets 41 | # correctly. The bug has been fixed in OVS v2.1.0. 42 | match = parser.OFPMatch() 43 | actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, 44 | ofproto.OFPCML_NO_BUFFER)] 45 | self.add_flow(datapath, 0, match, actions) 46 | 47 | def add_flow(self, datapath, priority, match, actions, buffer_id=None): 48 | ofproto = datapath.ofproto 49 | parser = datapath.ofproto_parser 50 | 51 | inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, 52 | actions)] 53 | if buffer_id: 54 | mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id, 55 | priority=priority, match=match, 56 | instructions=inst) 57 | else: 58 | mod = parser.OFPFlowMod(datapath=datapath, priority=priority, 59 | match=match, instructions=inst) 60 | datapath.send_msg(mod) 61 | 62 | @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) 63 | def _packet_in_handler(self, ev): 64 | # If you hit this you might want to increase 65 | # the "miss_send_length" of your switch 66 | if ev.msg.msg_len < ev.msg.total_len: 67 | self.logger.debug("packet truncated: only %s of %s bytes", 68 | ev.msg.msg_len, ev.msg.total_len) 69 | msg = ev.msg 70 | datapath = msg.datapath 71 | ofproto = datapath.ofproto 72 | parser = datapath.ofproto_parser 73 | in_port = msg.match['in_port'] 74 | 75 | pkt = packet.Packet(msg.data) 76 | eth = pkt.get_protocols(ethernet.ethernet)[0] 77 | dst = eth.dst 78 | src = eth.src 79 | dpid = datapath.id 80 | 81 | # ignore lldp and ipv6 packet 82 | if eth.ethertype == ether_types.ETH_TYPE_LLDP or eth.ethertype == ether_types.ETH_TYPE_IPV6: 83 | return 84 | 85 | self.logger.info("Packet In: %s %s -> %s | port:%s", 86 | dpid, src, dst, in_port) 87 | 88 | if eth.ethertype == ether_types.ETH_TYPE_ARP and dst == "ff:ff:ff:ff:ff:ff": 89 | arp_dst_ip = pkt.get_protocol(arp.arp).dst_ip 90 | if (dpid, src, arp_dst_ip) in self.arp_broadcast: 91 | if self.arp_broadcast[(dpid, src, arp_dst_ip)] != in_port: 92 | out = datapath.ofproto_parser.OFPPacketOut( 93 | datapath=datapath, 94 | buffer_id=datapath.ofproto.OFP_NO_BUFFER, 95 | in_port=in_port, 96 | actions=[], data=None) 97 | datapath.send_msg(out) 98 | self.logger.info('ARP Loop Maker Dropped!') 99 | 100 | return 101 | else: # learn arp broadcast table 102 | self.arp_broadcast[(dpid, src, arp_dst_ip)] = in_port 103 | 104 | self.mac_to_port.setdefault(dpid, {}) 105 | # learn a mac address to avoid FLOOD next time. 106 | self.mac_to_port[dpid][src] = in_port 107 | 108 | if dst in self.mac_to_port[dpid]: 109 | out_port = self.mac_to_port[dpid][dst] 110 | else: 111 | out_port = ofproto.OFPP_FLOOD 112 | 113 | actions = [parser.OFPActionOutput(out_port)] 114 | 115 | # install a flow to avoid packet_in next time 116 | if out_port != ofproto.OFPP_FLOOD: 117 | match = parser.OFPMatch(in_port=in_port, eth_dst=dst, eth_src=src) 118 | # verify if we have a valid buffer_id, if yes avoid to send both 119 | # flow_mod & packet_out 120 | if msg.buffer_id != ofproto.OFP_NO_BUFFER: 121 | self.add_flow(datapath, 1, match, actions, msg.buffer_id) 122 | return 123 | else: 124 | self.add_flow(datapath, 1, match, actions) 125 | data = None 126 | if msg.buffer_id == ofproto.OFP_NO_BUFFER: 127 | data = msg.data 128 | 129 | out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id, 130 | in_port=in_port, actions=actions, data=data) 131 | datapath.send_msg(out) 132 | 133 | 134 | class EastWestAPI(ControllerBase): 135 | def __init__(self, req, link, data, **config): 136 | super(EastWestAPI, self).__init__(req, link, data, **config) 137 | self.SMF_app = data[sba_instance_name] 138 | self.logger = logging.getLogger(self.__class__.__name__) 139 | self.authentication = { 140 | 'TEST': '033bd94b1168d7e4f0d644c3c95e35bf', 141 | 'URLLC': 'dfdc323ef40c8f38f5f022a5554f2dee', 142 | 'EMBB': 'e9406f9b456569f230a23d21464189f2', 143 | 'MMTC': '1d99331a7879c3c5b90998f8c3c6a9d6' 144 | } 145 | self.unauthenticated = Response( 146 | status=401, 147 | content_type='application/json', 148 | body=json.dumps( 149 | {'error': 'unauthenticated'}, 150 | indent=4 151 | ) + '\n' 152 | ) 153 | 154 | @route('mac-port-table', '/mac-port-table', methods=['GET']) 155 | def _mac_port_table(self, req, **kwargs): 156 | SMF_app = self.SMF_app 157 | body = json.dumps(SMF_app.mac_to_port, indent=4) + '\n' 158 | 159 | if 'Authentication' in req.headers: 160 | if req.headers['Authentication'] in self.authentication.values(): 161 | return Response(content_type='application/json', body=body) 162 | else: 163 | return self.unauthenticated 164 | else: 165 | return self.unauthenticated 166 | 167 | @route('arp-table', '/arp-table', methods=['GET']) 168 | def _arp_table(self, req, **kwargs): 169 | arp_broadcast = self.SMF_app.arp_broadcast 170 | arp_str_table = {} 171 | for key in arp_broadcast.keys(): 172 | arp_str_table[str(key)] = arp_broadcast[key] 173 | body = json.dumps(arp_str_table, indent=4) + '\n' 174 | 175 | if 'Authentication' in req.headers: 176 | if req.headers['Authentication'] in self.authentication.values(): 177 | return Response(content_type='application/json', body=body) 178 | else: 179 | return self.unauthenticated 180 | else: 181 | return self.unauthenticated 182 | -------------------------------------------------------------------------------- /formal-version/sba-udm-ctrl.py: -------------------------------------------------------------------------------- 1 | from ryu.base import app_manager 2 | from ryu.controller import ofp_event 3 | from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER 4 | from ryu.controller.handler import set_ev_cls 5 | from ryu.ofproto import ofproto_v1_3 6 | from ryu.lib.packet import packet 7 | from ryu.lib.packet import ethernet, ether_types, arp 8 | 9 | # REST Api Packages 10 | import json 11 | import logging 12 | from ryu.app.wsgi import WSGIApplication, ControllerBase, route 13 | from webob import Response 14 | 15 | sba_instance_name = 'SBA_UDM' 16 | 17 | 18 | class SBAudmCtrl(app_manager.RyuApp): 19 | OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] 20 | _CONTEXTS = {'wsgi': WSGIApplication} 21 | 22 | def __init__(self, *args, **kwargs): 23 | super(SBAudmCtrl, self).__init__(*args, **kwargs) 24 | self.mac_to_port = {} # mac address to inbound port table 25 | self.arp_broadcast = {} # arp broadcast inbound port table 26 | wsgi = kwargs['wsgi'] 27 | wsgi.register(EastWestAPI, {sba_instance_name: self}) 28 | 29 | @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER) 30 | def switch_features_handler(self, ev): 31 | datapath = ev.msg.datapath 32 | ofproto = datapath.ofproto 33 | parser = datapath.ofproto_parser 34 | 35 | # install table-miss flow entry 36 | # 37 | # We specify NO BUFFER to max_len of the output action due to 38 | # OVS bug. At this moment, if we specify a lesser number, e.g., 39 | # 128, OVS will send Packet-In with invalid buffer_id and 40 | # truncated packet data. In that case, we cannot output packets 41 | # correctly. The bug has been fixed in OVS v2.1.0. 42 | match = parser.OFPMatch() 43 | actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, 44 | ofproto.OFPCML_NO_BUFFER)] 45 | self.add_flow(datapath, 0, match, actions) 46 | 47 | def add_flow(self, datapath, priority, match, actions, buffer_id=None): 48 | ofproto = datapath.ofproto 49 | parser = datapath.ofproto_parser 50 | 51 | inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, 52 | actions)] 53 | if buffer_id: 54 | mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id, 55 | priority=priority, match=match, 56 | instructions=inst) 57 | else: 58 | mod = parser.OFPFlowMod(datapath=datapath, priority=priority, 59 | match=match, instructions=inst) 60 | datapath.send_msg(mod) 61 | 62 | @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) 63 | def _packet_in_handler(self, ev): 64 | # If you hit this you might want to increase 65 | # the "miss_send_length" of your switch 66 | if ev.msg.msg_len < ev.msg.total_len: 67 | self.logger.debug("packet truncated: only %s of %s bytes", 68 | ev.msg.msg_len, ev.msg.total_len) 69 | msg = ev.msg 70 | datapath = msg.datapath 71 | ofproto = datapath.ofproto 72 | parser = datapath.ofproto_parser 73 | in_port = msg.match['in_port'] 74 | 75 | pkt = packet.Packet(msg.data) 76 | eth = pkt.get_protocols(ethernet.ethernet)[0] 77 | dst = eth.dst 78 | src = eth.src 79 | dpid = datapath.id 80 | 81 | # ignore lldp and ipv6 packet 82 | if eth.ethertype == ether_types.ETH_TYPE_LLDP or eth.ethertype == ether_types.ETH_TYPE_IPV6: 83 | return 84 | 85 | self.logger.info("Packet In: %s %s -> %s | port:%s", 86 | dpid, src, dst, in_port) 87 | 88 | if eth.ethertype == ether_types.ETH_TYPE_ARP and dst == "ff:ff:ff:ff:ff:ff": 89 | arp_dst_ip = pkt.get_protocol(arp.arp).dst_ip 90 | if (dpid, src, arp_dst_ip) in self.arp_broadcast: 91 | if self.arp_broadcast[(dpid, src, arp_dst_ip)] != in_port: 92 | out = datapath.ofproto_parser.OFPPacketOut( 93 | datapath=datapath, 94 | buffer_id=datapath.ofproto.OFP_NO_BUFFER, 95 | in_port=in_port, 96 | actions=[], data=None) 97 | datapath.send_msg(out) 98 | self.logger.info('ARP Loop Maker Dropped!') 99 | 100 | return 101 | else: # learn arp broadcast table 102 | self.arp_broadcast[(dpid, src, arp_dst_ip)] = in_port 103 | 104 | self.mac_to_port.setdefault(dpid, {}) 105 | # learn a mac address to avoid FLOOD next time. 106 | self.mac_to_port[dpid][src] = in_port 107 | 108 | if dst in self.mac_to_port[dpid]: 109 | out_port = self.mac_to_port[dpid][dst] 110 | else: 111 | out_port = ofproto.OFPP_FLOOD 112 | 113 | actions = [parser.OFPActionOutput(out_port)] 114 | 115 | # install a flow to avoid packet_in next time 116 | if out_port != ofproto.OFPP_FLOOD: 117 | match = parser.OFPMatch(in_port=in_port, eth_dst=dst, eth_src=src) 118 | # verify if we have a valid buffer_id, if yes avoid to send both 119 | # flow_mod & packet_out 120 | if msg.buffer_id != ofproto.OFP_NO_BUFFER: 121 | self.add_flow(datapath, 1, match, actions, msg.buffer_id) 122 | return 123 | else: 124 | self.add_flow(datapath, 1, match, actions) 125 | data = None 126 | if msg.buffer_id == ofproto.OFP_NO_BUFFER: 127 | data = msg.data 128 | 129 | out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id, 130 | in_port=in_port, actions=actions, data=data) 131 | datapath.send_msg(out) 132 | 133 | 134 | class EastWestAPI(ControllerBase): 135 | def __init__(self, req, link, data, **config): 136 | super(EastWestAPI, self).__init__(req, link, data, **config) 137 | self.UDM_app = data[sba_instance_name] 138 | self.logger = logging.getLogger(self.__class__.__name__) 139 | self.authentication = { 140 | 'TEST': '033bd94b1168d7e4f0d644c3c95e35bf', 141 | 'URLLC': 'dfdc323ef40c8f38f5f022a5554f2dee', 142 | 'EMBB': 'e9406f9b456569f230a23d21464189f2', 143 | 'MMTC': '1d99331a7879c3c5b90998f8c3c6a9d6' 144 | } 145 | self.unauthenticated = Response( 146 | status=401, 147 | content_type='application/json', 148 | body=json.dumps( 149 | {'error': 'unauthenticated'}, 150 | indent=4 151 | ) + '\n' 152 | ) 153 | 154 | @route('mac-port-table', '/mac-port-table', methods=['GET']) 155 | def _mac_port_table(self, req, **kwargs): 156 | UDM_app = self.UDM_app 157 | body = json.dumps(UDM_app.mac_to_port, indent=4) + '\n' 158 | 159 | if 'Authentication' in req.headers: 160 | if req.headers['Authentication'] in self.authentication.values(): 161 | return Response(content_type='application/json', body=body) 162 | else: 163 | return self.unauthenticated 164 | else: 165 | return self.unauthenticated 166 | 167 | @route('arp-table', '/arp-table', methods=['GET']) 168 | def _arp_table(self, req, **kwargs): 169 | arp_broadcast = self.UDM_app.arp_broadcast 170 | arp_str_table = {} 171 | for key in arp_broadcast.keys(): 172 | arp_str_table[str(key)] = arp_broadcast[key] 173 | body = json.dumps(arp_str_table, indent=4) + '\n' 174 | 175 | if 'Authentication' in req.headers: 176 | if req.headers['Authentication'] in self.authentication.values(): 177 | return Response(content_type='application/json', body=body) 178 | else: 179 | return self.unauthenticated 180 | else: 181 | return self.unauthenticated 182 | -------------------------------------------------------------------------------- /formal-version/servers/d_DN.py: -------------------------------------------------------------------------------- 1 | import json 2 | import time 3 | import sys 4 | import threading 5 | import socket 6 | 7 | from h2.connection import H2Connection 8 | from h2.events import RequestReceived, DataReceived 9 | 10 | # Test Mode: Listen localhost:9003 11 | # Otherwise: Listen 10.0.5.1:8080 12 | TEST_MODE = True if len(sys.argv) == 2 and sys.argv[1] == '--test' else False 13 | HOST = 'localhost' if TEST_MODE else '10.0.5.1' 14 | LISTEN_PORT = 9003 if TEST_MODE else 8080 15 | 16 | 17 | class RecieverConnection(object): 18 | "An object of simple HTTP/2 connection" 19 | 20 | def __init__(self, sock, TEST_MODE): 21 | self.sock = sock 22 | self.TEST_MODE = TEST_MODE 23 | self.conn = H2Connection(client_side=False) 24 | self.rx_headers = False 25 | self.stream_id = False 26 | 27 | def run_forever(self): 28 | self.conn.initiate_connection() 29 | self.sock.sendall(self.conn.data_to_send()) 30 | 31 | while True: 32 | data = self.sock.recv(65535) 33 | if not data: 34 | break 35 | 36 | events = self.conn.receive_data(data) 37 | 38 | for event in events: 39 | if isinstance(event, RequestReceived): 40 | print(dict(event.headers)) 41 | self.rx_headers = event.headers 42 | self.stream_id = event.stream_id 43 | elif isinstance(event, DataReceived): 44 | print(event.data) 45 | 46 | if self.rx_headers: 47 | print('==========DN') 48 | self.send_response() 49 | 50 | data_to_send = self.conn.data_to_send() 51 | if data_to_send: 52 | self.sock.sendall(data_to_send) 53 | 54 | def send_response(self): 55 | response_data = json.dumps({'Content': 'Data recieved by Data Network'}) 56 | self.conn.send_headers( 57 | stream_id=self.stream_id, 58 | headers=[ 59 | (':status', '200'), 60 | ('server', 'dp_DN-h2-server/1.0'), 61 | ('content-length', str(len(response_data))), 62 | ('content-type', 'application/json'), 63 | ('rx-timestamp', '{:.6f}'.format(time.time().real)) 64 | ], 65 | ) 66 | self.conn.send_data( 67 | stream_id=self.stream_id, 68 | data=response_data, 69 | end_stream=True 70 | ) 71 | 72 | 73 | print('HTTP/2 server started at http://{}:{}'.format('localhost' if TEST_MODE else '10.0.5.1', LISTEN_PORT)) 74 | 75 | sock = socket.socket() 76 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 77 | sock.bind(('0.0.0.0', int(LISTEN_PORT))) 78 | sock.listen(5) 79 | 80 | while True: 81 | try: 82 | connection = RecieverConnection(sock.accept()[0], TEST_MODE) 83 | th = threading.Thread(target=connection.run_forever) 84 | th.start() 85 | except(SystemExit, KeyboardInterrupt): 86 | break 87 | -------------------------------------------------------------------------------- /formal-version/servers/d_UPF_h0.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import json 3 | import threading 4 | import socket 5 | 6 | from h2.connection import H2Connection 7 | from h2.events import RequestReceived, DataReceived 8 | from hyper import HTTP20Connection 9 | 10 | # Test Mode: Listen: localhost:9002 11 | # Foward: localhost:9003 12 | # Otherwise: Listen: 10.0.4.1:8080 13 | # Foward: 10.0.5.1:8080 14 | TEST_MODE = True if len(sys.argv) == 2 and sys.argv[1] == '--test' else False 15 | LISTEN_PORT = 9002 if TEST_MODE else 8080 16 | SEND_PORT = 9003 if TEST_MODE else 8080 17 | 18 | 19 | class UPF(object): 20 | "An object of simple HTTP/2 connection" 21 | 22 | # control plane packet buffer database 23 | CP_BUFFER = [] 24 | 25 | def __init__(self, sock, TEST_MODE): 26 | self.sock = sock 27 | self.TEST_MODE = TEST_MODE 28 | self.conn = H2Connection(client_side=False) 29 | 30 | # Space for incoming request headers and body 31 | self.rx_headers = False 32 | self.rx_body = False 33 | self.stream_id = False 34 | 35 | self.cp = False # True when this pkt is from control plane, false when user plane 36 | 37 | # Sapce for response headers and body 38 | self.res_headers = False 39 | self.res_rxts = False 40 | self.res_body = False 41 | 42 | def run_forever(self): 43 | self.conn.initiate_connection() 44 | self.sock.sendall(self.conn.data_to_send()) 45 | 46 | while True: 47 | data = self.sock.recv(65535) 48 | if not data: 49 | break 50 | 51 | events = self.conn.receive_data(data) 52 | 53 | for event in events: 54 | if isinstance(event, RequestReceived): 55 | self.rx_headers = event.headers 56 | self.stream_id = event.stream_id 57 | print(dict(self.rx_headers)) 58 | elif isinstance(event, DataReceived): 59 | self.rx_body = event.data 60 | print(self.rx_body) 61 | 62 | # Check if packet is from UP or CP and do the right thing 63 | if self.rx_headers and self.rx_body: 64 | if dict(self.rx_headers)['plane'] == 'control': 65 | self.cp = True 66 | self.buffer_control_plane_pkt() 67 | self.send_response() 68 | elif dict(self.rx_headers)['plane'] == 'user': 69 | self.cp = False 70 | # Wait until control packet comes 71 | # while True: 72 | # if self.control_plane_buffer_status() == 'SUCCESS': 73 | # break 74 | self.foward_request() 75 | self.send_response() 76 | print('----------') 77 | 78 | data_to_send = self.conn.data_to_send() 79 | if data_to_send: 80 | self.sock.sendall(data_to_send) 81 | 82 | def buffer_control_plane_pkt(self): 83 | pkt_id = str(dict(self.rx_headers)['id']) 84 | body_json = json.loads(self.rx_body) 85 | print('RESULT DICT: {}'.format(body_json['RESULT'])) 86 | # check if all result is true 87 | result = all(x for x in body_json['RESULT'].values()) 88 | print('RESULT: {}'.format(result)) 89 | pkt_buffer = { 90 | 'id': pkt_id, 91 | 'RESULT': result 92 | } 93 | UPF.CP_BUFFER.append(pkt_buffer) 94 | 95 | def control_plane_buffer_status(self): 96 | """ 97 | Check control plane buffer and return status 98 | 99 | NOT FOUND: Current UP packet id not found in CP buffer 100 | SUCCESS: Current UP packet id found in CP buffer and result is good 101 | FAIL: Current UP packet id found in CP buffer but result is bad 102 | """ 103 | pkt_id = str(dict(self.rx_headers)['id']) 104 | found_idx = -1 105 | status = 'NOT FOUND' 106 | 107 | for idx, buffer in enumerate(UPF.CP_BUFFER): 108 | if buffer['id'] == pkt_id: 109 | if buffer['RESULT']: 110 | status = 'SUCCESS' 111 | else: 112 | status = 'FAIL' 113 | 114 | found_idx = idx 115 | break 116 | 117 | if found_idx != -1: 118 | del UPF.CP_BUFFER[found_idx] 119 | 120 | return status 121 | 122 | def send_response(self): 123 | body = json.dumps({'Content': 'Recieved by UPF'}).encode('utf-8') if self.cp else self.res_body 124 | headers = [ 125 | (':status', '200'), 126 | ('server', 'dp_UPF-h2-server/1.0'), 127 | ('content-length', str(len(body))), 128 | ('content-type', 'application/json') 129 | ] 130 | if not self.cp: 131 | headers.append(('rx-timestamp', self.res_rxts)) 132 | 133 | self.conn.send_headers( 134 | stream_id=self.stream_id, 135 | headers=headers 136 | ) 137 | self.conn.send_data( 138 | stream_id=self.stream_id, 139 | data=body, 140 | end_stream=True 141 | ) 142 | 143 | def foward_request(self): 144 | send_conn = HTTP20Connection('0.0.0.0:9003' if self.TEST_MODE else '10.0.5.1:8080') 145 | send_conn.request('POST', '/', headers=dict(self.rx_headers), body=self.rx_body) 146 | resp = send_conn.get_response() 147 | if resp: 148 | print('Fowarded this request to DN and got response') 149 | self.res_body = resp.read() 150 | self.res_rxts = resp.headers['rx-timestamp'][0] 151 | 152 | 153 | print('Data Plane UPF server started at http://{}:{}'.format('0.0.0.0' if TEST_MODE else '10.0.4.1', LISTEN_PORT)) 154 | print('Packets will foward to http://{}:{}'.format('localhost' if TEST_MODE else '10.0.5.1', SEND_PORT)) 155 | 156 | sock = socket.socket() 157 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 158 | sock.bind(('0.0.0.0', int(LISTEN_PORT))) 159 | sock.listen(5) 160 | 161 | while True: 162 | try: 163 | connection = UPF(sock.accept()[0], TEST_MODE) 164 | th = threading.Thread(target=connection.run_forever) 165 | th.start() 166 | except(SystemExit, KeyboardInterrupt): 167 | break 168 | -------------------------------------------------------------------------------- /formal-version/servers/n_URLLC_h0.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import json 3 | import threading 4 | import socket 5 | 6 | from h2.connection import H2Connection 7 | from h2.events import RequestReceived 8 | from hyper import HTTP20Connection 9 | 10 | # Test Mode: Listen: localhost:9004 11 | # Foward: localhost:9010 12 | # Otherwise: Listen: 10.0.2.1:8080 13 | # Foward: 10.0.3.4:8080 14 | TEST_MODE = True if len(sys.argv) == 2 and sys.argv[1] == '--test' else False 15 | LISTEN_PORT = 9004 if TEST_MODE else 8080 16 | SEND_PORT = 9010 if TEST_MODE else 8080 17 | 18 | LOCK = threading.Lock() 19 | 20 | 21 | class NFVURLLCConnection(object): 22 | "An object of simple HTTP/2 connection" 23 | 24 | def __init__(self, sock, TEST_MODE, lock): 25 | self.sock = sock 26 | self.TEST_MODE = TEST_MODE 27 | self.lock = lock 28 | self.conn = H2Connection(client_side=False) 29 | 30 | # Space for incoming request headers 31 | self.rx_headers = False 32 | self.stream_id = False 33 | 34 | def run_forever(self): 35 | self.conn.initiate_connection() 36 | self.sock.sendall(self.conn.data_to_send()) 37 | 38 | while True: 39 | data = self.sock.recv(65535) 40 | if not data: 41 | break 42 | 43 | events = self.conn.receive_data(data) 44 | 45 | for event in events: 46 | if isinstance(event, RequestReceived): 47 | self.rx_headers = event.headers 48 | self.stream_id = event.stream_id 49 | 50 | # Foward request, wait for its response, then send response to where this request from 51 | if self.rx_headers: 52 | self.send_response() 53 | self.foward_request() 54 | 55 | data_to_send = self.conn.data_to_send() 56 | if data_to_send: 57 | self.sock.sendall(data_to_send) 58 | 59 | def send_response(self): 60 | body = json.dumps({'Content': 'Recieved by NFVSM'}).encode('utf-8') 61 | self.conn.send_headers( 62 | stream_id=self.stream_id, 63 | headers=[ 64 | (':status', '200'), 65 | ('server', 'n_URLLC-h2-server/1.0'), 66 | ('content-length', str(len(body))), 67 | ('content-type', 'application/json'), 68 | ('id', str(dict(self.rx_headers)['id'])) 69 | ], 70 | ) 71 | self.conn.send_data( 72 | stream_id=self.stream_id, 73 | data=body, 74 | end_stream=True 75 | ) 76 | 77 | def foward_request(self): 78 | send_conn = HTTP20Connection('localhost:9010' if self.TEST_MODE else '10.0.3.4:8080') 79 | fw_body = json.dumps({ 80 | 'SBA_ENTITY': ['AMF', 'NRF', 'AUSF', 'UDM', 'SMF'], 81 | 'MODE': { 82 | 'AMF': 'FAST', 83 | 'NRF': 'FAST', 84 | 'AUSF': 'FAST', 85 | 'UDM': 'FAST', 86 | 'SMF': 'FAST' 87 | } 88 | }).encode('utf-8') 89 | send_conn.request('POST', '/', headers=dict(self.rx_headers), body=fw_body) 90 | resp = send_conn.get_response() 91 | if resp: 92 | self.lock.acquire() 93 | print('Fowarded packet to SBAES') 94 | self.res_body = resp.read() 95 | print('FW Header: {}'.format(dict(self.rx_headers))) 96 | print('FW Body: {}'.format(fw_body)) 97 | print('Response: {}'.format(self.res_body)) 98 | print('==========FW') 99 | self.lock.release() 100 | 101 | 102 | print('NFV Service URLLC server started at http://{}:{}'.format('0.0.0.0' if TEST_MODE else '10.0.2.1', LISTEN_PORT)) 103 | print('Packet will foward to SBA Entity AMF at http://{}:{}'.format('0.0.0.0' if TEST_MODE else '10.0.3.4', SEND_PORT)) 104 | 105 | sock = socket.socket() 106 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 107 | sock.bind(('0.0.0.0', int(LISTEN_PORT))) 108 | sock.listen(5) 109 | 110 | while True: 111 | try: 112 | connection = NFVURLLCConnection(sock.accept()[0], TEST_MODE, LOCK) 113 | th = threading.Thread(target=connection.run_forever) 114 | th.start() 115 | except(SystemExit, KeyboardInterrupt): 116 | break 117 | -------------------------------------------------------------------------------- /formal-version/servers/n_eMBB_h0.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import json 3 | import threading 4 | import socket 5 | 6 | from h2.connection import H2Connection 7 | from h2.events import RequestReceived 8 | from hyper import HTTP20Connection 9 | 10 | # Test Mode: Listen: localhost:9005 11 | # Foward: localhost:9010 12 | # Otherwise: Listen: 10.0.2.2:8080 13 | # Foward: 10.0.3.4:8080 14 | TEST_MODE = True if len(sys.argv) == 2 and sys.argv[1] == '--test' else False 15 | LISTEN_PORT = 9005 if TEST_MODE else 8080 16 | SEND_PORT = 9010 if TEST_MODE else 8080 17 | 18 | LOCK = threading.Lock() 19 | 20 | 21 | class NFVeMBBConnection(object): 22 | "An object of simple HTTP/2 connection" 23 | 24 | def __init__(self, sock, TEST_MODE, lock): 25 | self.sock = sock 26 | self.TEST_MODE = TEST_MODE 27 | self.lock = lock 28 | self.conn = H2Connection(client_side=False) 29 | 30 | # Space for incoming request headers 31 | self.rx_headers = False 32 | self.stream_id = False 33 | 34 | def run_forever(self): 35 | self.conn.initiate_connection() 36 | self.sock.sendall(self.conn.data_to_send()) 37 | 38 | while True: 39 | data = self.sock.recv(65535) 40 | if not data: 41 | break 42 | 43 | events = self.conn.receive_data(data) 44 | 45 | for event in events: 46 | if isinstance(event, RequestReceived): 47 | self.rx_headers = event.headers 48 | self.stream_id = event.stream_id 49 | 50 | # Foward request, wait for its response, then send response to where this request from 51 | if self.rx_headers: 52 | self.send_response() 53 | self.foward_request() 54 | 55 | data_to_send = self.conn.data_to_send() 56 | if data_to_send: 57 | self.sock.sendall(data_to_send) 58 | 59 | def send_response(self): 60 | body = json.dumps({'Content': 'Recieved by NFVSM'}).encode('utf-8') 61 | self.conn.send_headers( 62 | stream_id=self.stream_id, 63 | headers=[ 64 | (':status', '200'), 65 | ('server', 'n_eMBB-h2-server/1.0'), 66 | ('content-length', str(len(body))), 67 | ('content-type', 'application/json'), 68 | ('id', str(dict(self.rx_headers)['id'])) 69 | ], 70 | ) 71 | self.conn.send_data( 72 | stream_id=self.stream_id, 73 | data=body, 74 | end_stream=True 75 | ) 76 | 77 | def foward_request(self): 78 | send_conn = HTTP20Connection( 79 | 'localhost:9010' if self.TEST_MODE else '10.0.3.4:8080') 80 | fw_body = json.dumps({ 81 | 'SBA_ENTITY': ['AMF', 'NRF', 'AUSF', 'UDM', 'PCF', 'AF', 'SMF'], 82 | 'MODE': { 83 | 'AMF': 'FAST', 84 | 'NRF': 'REGULAR', 85 | 'AUSF': 'REGULAR', 86 | 'UDM': 'REGULAR', 87 | 'PCF': 'WAITABLE', 88 | 'AF': 'FAST', 89 | 'SMF': 'FAST' 90 | } 91 | }).encode('utf-8') 92 | send_conn.request( 93 | 'POST', '/', headers=dict(self.rx_headers), body=fw_body) 94 | resp = send_conn.get_response() 95 | if resp: 96 | self.lock.acquire() 97 | print('Fowarded packet to SBAES') 98 | self.res_body = resp.read() 99 | print('FW Header: {}'.format(dict(self.rx_headers))) 100 | print('FW Body: {}'.format(fw_body)) 101 | print('Response: {}'.format(self.res_body)) 102 | print('==========FW') 103 | self.lock.release() 104 | 105 | 106 | print('NFV Service eMBB server started at http://{}:{}'.format( 107 | '0.0.0.0' if TEST_MODE else '10.0.2.2', LISTEN_PORT)) 108 | print('Packet will foward to SBA Entity AMF at http://{}:{}'.format( 109 | '0.0.0.0' if TEST_MODE else '10.0.3.4', SEND_PORT)) 110 | 111 | sock = socket.socket() 112 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 113 | sock.bind(('0.0.0.0', int(LISTEN_PORT))) 114 | sock.listen(5) 115 | 116 | while True: 117 | try: 118 | connection = NFVeMBBConnection(sock.accept()[0], TEST_MODE, LOCK) 119 | th = threading.Thread(target=connection.run_forever) 120 | th.start() 121 | except(SystemExit, KeyboardInterrupt): 122 | break 123 | -------------------------------------------------------------------------------- /formal-version/servers/n_mMTC_h0.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import json 3 | import threading 4 | import socket 5 | 6 | from h2.connection import H2Connection 7 | from h2.events import RequestReceived 8 | from hyper import HTTP20Connection 9 | 10 | # Test Mode: Listen: localhost:9006 11 | # Foward: localhost:9010 12 | # Otherwise: Listen: 10.0.2.3:8080 13 | # Foward: 10.0.3.4:8080 14 | TEST_MODE = True if len(sys.argv) == 2 and sys.argv[1] == '--test' else False 15 | LISTEN_PORT = 9006 if TEST_MODE else 8080 16 | SEND_PORT = 9010 if TEST_MODE else 8080 17 | 18 | LOCK = threading.Lock() 19 | 20 | 21 | class NFVeMBBConnection(object): 22 | "An object of simple HTTP/2 connection" 23 | 24 | def __init__(self, sock, TEST_MODE, lock): 25 | self.sock = sock 26 | self.TEST_MODE = TEST_MODE 27 | self.lock = lock 28 | self.conn = H2Connection(client_side=False) 29 | 30 | # Space for incoming request headers 31 | self.rx_headers = False 32 | self.stream_id = False 33 | 34 | def run_forever(self): 35 | self.conn.initiate_connection() 36 | self.sock.sendall(self.conn.data_to_send()) 37 | 38 | while True: 39 | data = self.sock.recv(65535) 40 | if not data: 41 | break 42 | 43 | events = self.conn.receive_data(data) 44 | 45 | for event in events: 46 | if isinstance(event, RequestReceived): 47 | self.rx_headers = event.headers 48 | self.stream_id = event.stream_id 49 | 50 | # Foward request, wait for its response, then send response to where this request from 51 | if self.rx_headers: 52 | self.send_response() 53 | self.foward_request() 54 | 55 | data_to_send = self.conn.data_to_send() 56 | if data_to_send: 57 | self.sock.sendall(data_to_send) 58 | 59 | def send_response(self): 60 | body = json.dumps({'Content': 'Recieved by NFVSM'}).encode('utf-8') 61 | self.conn.send_headers( 62 | stream_id=self.stream_id, 63 | headers=[ 64 | (':status', '200'), 65 | ('server', 'n_mMTC-h2-server/1.0'), 66 | ('content-length', str(len(body))), 67 | ('content-type', 'application/json'), 68 | ('id', str(dict(self.rx_headers)['id'])) 69 | ], 70 | ) 71 | self.conn.send_data( 72 | stream_id=self.stream_id, 73 | data=body, 74 | end_stream=True 75 | ) 76 | 77 | def foward_request(self): 78 | send_conn = HTTP20Connection( 79 | 'localhost:9010' if self.TEST_MODE else '10.0.3.4:8080') 80 | fw_body = json.dumps({ 81 | 'SBA_ENTITY': ['AMF', 'NRF', 'AUSF', 'UDM', 'PCF', 'SMF'], 82 | 'MODE': { 83 | 'AMF': 'WAITABLE', 84 | 'NRF': 'REGULAR', 85 | 'AUSF': 'WAITABLE', 86 | 'UDM': 'REGULAR', 87 | 'PCF': 'REGULAR', 88 | 'SMF': 'FAST' 89 | } 90 | }).encode('utf-8') 91 | send_conn.request( 92 | 'POST', '/', headers=dict(self.rx_headers), body=fw_body) 93 | resp = send_conn.get_response() 94 | if resp: 95 | self.lock.acquire() 96 | print('Fowarded packet to SBAES') 97 | self.res_body = resp.read() 98 | print('FW Header: {}'.format(dict(self.rx_headers))) 99 | print('FW Body: {}'.format(fw_body)) 100 | print('Response: {}'.format(self.res_body)) 101 | print('==========FW') 102 | self.lock.release() 103 | 104 | 105 | print('NFV Service mMTC server started at http://{}:{}'.format( 106 | '0.0.0.0' if TEST_MODE else '10.0.2.3', LISTEN_PORT)) 107 | print('Packet will foward to SBA Entity AMF at http://{}:{}'.format( 108 | '0.0.0.0' if TEST_MODE else '10.0.3.4', SEND_PORT)) 109 | 110 | sock = socket.socket() 111 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 112 | sock.bind(('0.0.0.0', int(LISTEN_PORT))) 113 | sock.listen(5) 114 | 115 | while True: 116 | try: 117 | connection = NFVeMBBConnection(sock.accept()[0], TEST_MODE, LOCK) 118 | th = threading.Thread(target=connection.run_forever) 119 | th.start() 120 | except(SystemExit, KeyboardInterrupt): 121 | break 122 | -------------------------------------------------------------------------------- /formal-version/servers/s_AF_h0.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import json 3 | import threading 4 | import socket 5 | 6 | from h2.connection import H2Connection 7 | from h2.events import RequestReceived, DataReceived 8 | from hyper import HTTP20Connection 9 | 10 | # Test Mode: Listen: localhost:9013 11 | # Otherwise: Listen: 10.0.3.7:8080 12 | TEST_MODE = True if len(sys.argv) == 2 and sys.argv[1] == '--test' else False 13 | LISTEN_PORT = 9013 if TEST_MODE else 8080 14 | 15 | # SBA Entity Running Mode: FAST, REGULAR, WAITABLE 16 | 17 | LOCK = threading.Lock() 18 | 19 | 20 | class SBAAFConnection(object): 21 | "An object of simple HTTP/2 connection" 22 | 23 | def __init__(self, sock, TEST_MODE, lock): 24 | self.sock = sock 25 | self.TEST_MODE = TEST_MODE 26 | self.lock = lock 27 | self.conn = H2Connection(client_side=False) 28 | 29 | # Space for incoming request headers 30 | self.rx_headers = False 31 | self.rx_body = False 32 | self.stream_id = False 33 | 34 | self.rx_config = 'REGULAR' # Entity comsuming mode from header 35 | self.pkt_rlt = False # Entity comsuming result 36 | self.fw_body = {} # Body for fowarding 37 | 38 | def run_forever(self): 39 | self.conn.initiate_connection() 40 | self.sock.sendall(self.conn.data_to_send()) 41 | 42 | while True: 43 | data = self.sock.recv(65535) 44 | if not data: 45 | break 46 | 47 | events = self.conn.receive_data(data) 48 | 49 | for event in events: 50 | if isinstance(event, RequestReceived): 51 | self.rx_headers = event.headers 52 | self.stream_id = event.stream_id 53 | elif isinstance(event, DataReceived): 54 | self.rx_body = event.data 55 | 56 | # Foward request, wait for its response, then send response to where this request from 57 | if self.rx_headers and self.rx_body: 58 | self.send_response() 59 | self.resource_providing() 60 | if self.fw_body != {}: 61 | self.foward_request() 62 | else: 63 | print('Fowarding Failed.') 64 | 65 | data_to_send = self.conn.data_to_send() 66 | if data_to_send: 67 | self.sock.sendall(data_to_send) 68 | 69 | def resource_providing(self): 70 | # Parsing Request Body 71 | body_json = json.loads(self.rx_body) 72 | print(body_json) 73 | self.rx_config = str(body_json['MODE']['AF']) 74 | self.fw_body = { 75 | 'RESULT': body_json['RESULT'] 76 | } 77 | ents = [str(x) for x in body_json['SBA_ENTITY']] 78 | ents.pop(0) # delete AF in entities list 79 | confs = {str(k): str(v) for k, v in body_json['MODE'].items()} 80 | confs.pop('AF', None) # delete AF in config table 81 | 82 | # Fill into fowarding body 83 | self.fw_body.setdefault('SBA_ENTITY', []) 84 | self.fw_body.setdefault('MODE', {}) 85 | self.fw_body.setdefault('RESULT', {}) 86 | self.fw_body['SBA_ENTITY'] = ents 87 | self.fw_body['MODE'] = confs 88 | self.fw_body['RESULT']['AF'] = True # Always gives True for testing 89 | self.lock.acquire() 90 | print('Recieved Packet.\nMode: {}'.format(self.rx_config)) 91 | print('RX Header: {}'.format(self.rx_headers)) 92 | print('RX Body: {}'.format(body_json)) 93 | print('==========RX') 94 | self.lock.release() 95 | 96 | def send_response(self): 97 | body = json.dumps( 98 | {'Content': 'Recieved by SBAES - AF'}).encode('utf-8') 99 | self.conn.send_headers( 100 | stream_id=self.stream_id, 101 | headers=[ 102 | (':status', '200'), 103 | ('server', 's_AF-h2-server/1.0'), 104 | ('content-length', str(len(body))), 105 | ('content-type', 'application/json'), 106 | ('id', str(dict(self.rx_headers)['id'])) 107 | ], 108 | ) 109 | self.conn.send_data( 110 | stream_id=self.stream_id, 111 | data=body, 112 | end_stream=True 113 | ) 114 | 115 | def foward_request(self): 116 | fw_table = { 117 | 'NRF': 'localhost:9007', 118 | 'AUSF': 'localhost:9008', 119 | 'UDM': 'localhost:9009', 120 | 'AMF': 'localhost:9010', 121 | 'SMF': 'localhost:9011', 122 | 'PCF': 'localhost:9012', 123 | 'AF': 'localhost:9013' 124 | } if self.TEST_MODE else { 125 | 'NRF': '10.0.3.1:8080', 126 | 'AUSF': '10.0.3.2:8080', 127 | 'UDM': '10.0.3.3:8080', 128 | 'AMF': '10.0.3.4:8080', 129 | 'SMF': '10.0.3.5:8080', 130 | 'PCF': '10.0.3.6:8080', 131 | 'AF': '10.0.3.7:8080' 132 | } 133 | next_ent = self.fw_body['SBA_ENTITY'][0] 134 | print('Fowarded packet to SBA Entity {} at http://{}'.format(next_ent, 135 | fw_table[next_ent])) # Next SBA Entity to foward to 136 | send_conn = HTTP20Connection(fw_table[next_ent]) 137 | fw_body = json.dumps(self.fw_body).encode('utf-8') 138 | send_conn.request( 139 | 'POST', '/', headers=dict(self.rx_headers), body=fw_body) 140 | resp = send_conn.get_response() 141 | if resp: 142 | self.lock.acquire() 143 | print('Fowarded packet to SBA Entity {} at http://{}'.format(next_ent, fw_table[next_ent])) 144 | self.res_body = resp.read() 145 | print('FW Header: {}'.format(dict(self.rx_headers))) 146 | print('FW Body: {}'.format(fw_body)) 147 | print('Response: {}'.format(self.res_body)) 148 | print('==========FW') 149 | self.lock.release() 150 | 151 | 152 | print('SBA Entity AF server started at http://{}:{}'.format( 153 | '0.0.0.0' if TEST_MODE else '10.0.3.7', LISTEN_PORT)) 154 | 155 | sock = socket.socket() 156 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 157 | sock.bind(('0.0.0.0', int(LISTEN_PORT))) 158 | sock.listen(5) 159 | 160 | while True: 161 | try: 162 | connection = SBAAFConnection(sock.accept()[0], TEST_MODE, LOCK) 163 | th = threading.Thread(target=connection.run_forever) 164 | th.start() 165 | except(SystemExit, KeyboardInterrupt): 166 | break 167 | -------------------------------------------------------------------------------- /formal-version/servers/s_AMF_h0.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import json 3 | import threading 4 | import socket 5 | 6 | from h2.connection import H2Connection 7 | from h2.events import RequestReceived, DataReceived 8 | from hyper import HTTP20Connection 9 | 10 | # Test Mode: Listen: localhost:9010 11 | # Otherwise: Listen: 10.0.3.4:8080 12 | TEST_MODE = True if len(sys.argv) == 2 and sys.argv[1] == '--test' else False 13 | LISTEN_PORT = 9010 if TEST_MODE else 8080 14 | 15 | # SBA Entity Running Mode: FAST, REGULAR, WAITABLE 16 | 17 | LOCK = threading.Lock() 18 | 19 | 20 | class SBAAMFConnection(object): 21 | "An object of simple HTTP/2 connection" 22 | 23 | def __init__(self, sock, TEST_MODE, lock): 24 | self.sock = sock 25 | self.TEST_MODE = TEST_MODE 26 | self.lock = lock 27 | self.conn = H2Connection(client_side=False) 28 | 29 | # Space for incoming request headers 30 | self.rx_headers = False 31 | self.rx_body = False 32 | self.stream_id = False 33 | 34 | self.rx_config = 'REGULAR' # Entity comsuming mode from header 35 | self.pkt_rlt = False # Entity comsuming result 36 | self.fw_body = {} # Body for fowarding 37 | 38 | def run_forever(self): 39 | self.conn.initiate_connection() 40 | self.sock.sendall(self.conn.data_to_send()) 41 | 42 | while True: 43 | data = self.sock.recv(65535) 44 | if not data: 45 | break 46 | 47 | events = self.conn.receive_data(data) 48 | 49 | for event in events: 50 | if isinstance(event, RequestReceived): 51 | self.rx_headers = event.headers 52 | self.stream_id = event.stream_id 53 | elif isinstance(event, DataReceived): 54 | self.rx_body = event.data 55 | 56 | # Foward request, wait for its response, then send response to where this request from 57 | if self.rx_headers and self.rx_body: 58 | self.send_response() 59 | self.resource_providing() 60 | if self.fw_body != {}: 61 | self.foward_request() 62 | else: 63 | print('Fowarding Failed.') 64 | 65 | data_to_send = self.conn.data_to_send() 66 | if data_to_send: 67 | self.sock.sendall(data_to_send) 68 | 69 | def resource_providing(self): 70 | # Parsing Request Body 71 | body_json = json.loads(self.rx_body) 72 | self.rx_config = str(body_json['MODE']['AMF']) 73 | ents = [str(x) for x in body_json['SBA_ENTITY']] 74 | ents.pop(0) # delete AMF in entities list 75 | confs = {str(k): str(v) for k, v in body_json['MODE'].items()} 76 | confs.pop('AMF', None) # delete AMF in config table 77 | 78 | # Fill into fowarding body 79 | self.fw_body.setdefault('SBA_ENTITY', []) 80 | self.fw_body.setdefault('MODE', {}) 81 | self.fw_body.setdefault('RESULT', {}) 82 | self.fw_body['SBA_ENTITY'] = ents 83 | self.fw_body['MODE'] = confs 84 | self.fw_body['RESULT']['AMF'] = True # Always gives True for testing 85 | self.lock.acquire() 86 | print('Recieved Packet.\nMode: {}'.format(self.rx_config)) 87 | print('RX Header: {}'.format(self.rx_headers)) 88 | print('RX Body: {}'.format(body_json)) 89 | print('==========RX') 90 | self.lock.release() 91 | 92 | def send_response(self): 93 | body = json.dumps({'Content': 'Recieved by SBAES - AMF'}).encode('utf-8') 94 | self.conn.send_headers( 95 | stream_id=self.stream_id, 96 | headers=[ 97 | (':status', '200'), 98 | ('server', 's_AMF-h2-server/1.0'), 99 | ('content-length', str(len(body))), 100 | ('content-type', 'application/json'), 101 | ('id', str(dict(self.rx_headers)['id'])) 102 | ], 103 | ) 104 | self.conn.send_data( 105 | stream_id=self.stream_id, 106 | data=body, 107 | end_stream=True 108 | ) 109 | 110 | def foward_request(self): 111 | fw_table = { 112 | 'NRF': 'localhost:9007', 113 | 'AUSF': 'localhost:9008', 114 | 'UDM': 'localhost:9009', 115 | 'AMF': 'localhost:9010', 116 | 'SMF': 'localhost:9011', 117 | 'PCF': 'localhost:9012', 118 | 'AF': 'localhost:9013' 119 | } if self.TEST_MODE else { 120 | 'NRF': '10.0.3.1:8080', 121 | 'AUSF': '10.0.3.2:8080', 122 | 'UDM': '10.0.3.3:8080', 123 | 'AMF': '10.0.3.4:8080', 124 | 'SMF': '10.0.3.5:8080', 125 | 'PCF': '10.0.3.6:8080', 126 | 'AF': '10.0.3.7:8080' 127 | } 128 | next_ent = self.fw_body['SBA_ENTITY'][0] 129 | print('Fowarded packet to SBA Entity {} at http://{}'.format(next_ent, 130 | fw_table[next_ent])) # Next SBA Entity to foward to 131 | send_conn = HTTP20Connection(fw_table[next_ent]) 132 | fw_body = json.dumps(self.fw_body).encode('utf-8') 133 | send_conn.request('POST', '/', headers=dict(self.rx_headers), body=fw_body) 134 | resp = send_conn.get_response() 135 | if resp: 136 | self.lock.acquire() 137 | print('Fowarded packet to SBA Entity {} at http://{}'.format(next_ent, fw_table[next_ent])) 138 | self.res_body = resp.read() 139 | print('FW Header: {}'.format(dict(self.rx_headers))) 140 | print('FW Body: {}'.format(fw_body)) 141 | print('Response: {}'.format(self.res_body)) 142 | print('==========FW') 143 | self.lock.release() 144 | 145 | 146 | print('SBA Entity AMF server started at http://{}:{}'.format( 147 | '0.0.0.0' if TEST_MODE else '10.0.3.4', LISTEN_PORT)) 148 | 149 | sock = socket.socket() 150 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 151 | sock.bind(('0.0.0.0', int(LISTEN_PORT))) 152 | sock.listen(5) 153 | 154 | while True: 155 | try: 156 | connection = SBAAMFConnection(sock.accept()[0], TEST_MODE, LOCK) 157 | th = threading.Thread(target=connection.run_forever) 158 | th.start() 159 | except(SystemExit, KeyboardInterrupt): 160 | break 161 | -------------------------------------------------------------------------------- /formal-version/servers/s_AUSF_h0.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import json 3 | import threading 4 | import socket 5 | 6 | from h2.connection import H2Connection 7 | from h2.events import RequestReceived, DataReceived 8 | from hyper import HTTP20Connection 9 | 10 | # Test Mode: Listen: localhost:9008 11 | # Otherwise: Listen: 10.0.3.2:8080 12 | TEST_MODE = True if len(sys.argv) == 2 and sys.argv[1] == '--test' else False 13 | LISTEN_PORT = 9008 if TEST_MODE else 8080 14 | 15 | # SBA Entity Running Mode: FAST, REGULAR, WAITABLE 16 | 17 | LOCK = threading.Lock() 18 | 19 | 20 | class SBAAUSFConnection(object): 21 | "An object of simple HTTP/2 connection" 22 | 23 | def __init__(self, sock, TEST_MODE, lock): 24 | self.sock = sock 25 | self.TEST_MODE = TEST_MODE 26 | self.lock = lock 27 | self.conn = H2Connection(client_side=False) 28 | 29 | # Space for incoming request headers 30 | self.rx_headers = False 31 | self.rx_body = False 32 | self.stream_id = False 33 | 34 | self.rx_config = 'REGULAR' # Entity comsuming mode from header 35 | self.pkt_rlt = False # Entity comsuming result 36 | self.fw_body = {} # Body for fowarding 37 | 38 | def run_forever(self): 39 | self.conn.initiate_connection() 40 | self.sock.sendall(self.conn.data_to_send()) 41 | 42 | while True: 43 | data = self.sock.recv(65535) 44 | if not data: 45 | break 46 | 47 | events = self.conn.receive_data(data) 48 | 49 | for event in events: 50 | if isinstance(event, RequestReceived): 51 | self.rx_headers = event.headers 52 | self.stream_id = event.stream_id 53 | elif isinstance(event, DataReceived): 54 | self.rx_body = event.data 55 | 56 | # Foward request, wait for its response, then send response to where this request from 57 | if self.rx_headers and self.rx_body: 58 | self.send_response() 59 | self.resource_providing() 60 | if self.fw_body != {}: 61 | self.foward_request() 62 | else: 63 | print('Fowarding Failed.') 64 | 65 | data_to_send = self.conn.data_to_send() 66 | if data_to_send: 67 | self.sock.sendall(data_to_send) 68 | 69 | def resource_providing(self): 70 | # Parsing Request Body 71 | body_json = json.loads(self.rx_body) 72 | print(body_json) 73 | self.rx_config = str(body_json['MODE']['AUSF']) 74 | self.fw_body = { 75 | 'RESULT': body_json['RESULT'] 76 | } 77 | ents = [str(x) for x in body_json['SBA_ENTITY']] 78 | ents.pop(0) # delete AUSF in entities list 79 | confs = {str(k): str(v) for k, v in body_json['MODE'].items()} 80 | confs.pop('AUSF', None) # delete AUSF in config table 81 | 82 | # Fill into fowarding body 83 | self.fw_body.setdefault('SBA_ENTITY', []) 84 | self.fw_body.setdefault('MODE', {}) 85 | self.fw_body.setdefault('RESULT', {}) 86 | self.fw_body['SBA_ENTITY'] = ents 87 | self.fw_body['MODE'] = confs 88 | self.fw_body['RESULT']['AUSF'] = True # Always gives True for testing 89 | self.lock.acquire() 90 | print('Recieved Packet.\nMode: {}'.format(self.rx_config)) 91 | print('RX Header: {}'.format(self.rx_headers)) 92 | print('RX Body: {}'.format(body_json)) 93 | print('==========RX') 94 | self.lock.release() 95 | 96 | def send_response(self): 97 | body = json.dumps( 98 | {'Content': 'Recieved by SBAES - AUSF'}).encode('utf-8') 99 | self.conn.send_headers( 100 | stream_id=self.stream_id, 101 | headers=[ 102 | (':status', '200'), 103 | ('server', 's_AUSF-h2-server/1.0'), 104 | ('content-length', str(len(body))), 105 | ('content-type', 'application/json'), 106 | ('id', str(dict(self.rx_headers)['id'])) 107 | ], 108 | ) 109 | self.conn.send_data( 110 | stream_id=self.stream_id, 111 | data=body, 112 | end_stream=True 113 | ) 114 | 115 | def foward_request(self): 116 | fw_table = { 117 | 'NRF': 'localhost:9007', 118 | 'AUSF': 'localhost:9008', 119 | 'UDM': 'localhost:9009', 120 | 'AMF': 'localhost:9010', 121 | 'SMF': 'localhost:9011', 122 | 'PCF': 'localhost:9012', 123 | 'AF': 'localhost:9013' 124 | } if self.TEST_MODE else { 125 | 'NRF': '10.0.3.1:8080', 126 | 'AUSF': '10.0.3.2:8080', 127 | 'UDM': '10.0.3.3:8080', 128 | 'AMF': '10.0.3.4:8080', 129 | 'SMF': '10.0.3.5:8080', 130 | 'PCF': '10.0.3.6:8080', 131 | 'AF': '10.0.3.7:8080' 132 | } 133 | next_ent = self.fw_body['SBA_ENTITY'][0] 134 | print('Fowarded packet to SBA Entity {} at http://{}'.format(next_ent, fw_table[next_ent])) # Next SBA Entity to foward to 135 | send_conn = HTTP20Connection(fw_table[next_ent]) 136 | fw_body = json.dumps(self.fw_body).encode('utf-8') 137 | send_conn.request( 138 | 'POST', '/', headers=dict(self.rx_headers), body=fw_body) 139 | resp = send_conn.get_response() 140 | if resp: 141 | self.lock.acquire() 142 | print('Fowarded packet to SBA Entity {} at http://{}'.format(next_ent, fw_table[next_ent])) 143 | self.res_body = resp.read() 144 | print('FW Header: {}'.format(dict(self.rx_headers))) 145 | print('FW Body: {}'.format(fw_body)) 146 | print('Response: {}'.format(self.res_body)) 147 | print('==========FW') 148 | self.lock.release() 149 | 150 | 151 | print('SBA Entity AMF server started at http://{}:{}'.format( 152 | '0.0.0.0' if TEST_MODE else '10.0.3.2', LISTEN_PORT)) 153 | 154 | sock = socket.socket() 155 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 156 | sock.bind(('0.0.0.0', int(LISTEN_PORT))) 157 | sock.listen(5) 158 | 159 | while True: 160 | try: 161 | connection = SBAAUSFConnection(sock.accept()[0], TEST_MODE, LOCK) 162 | th = threading.Thread(target=connection.run_forever) 163 | th.start() 164 | except(SystemExit, KeyboardInterrupt): 165 | break 166 | -------------------------------------------------------------------------------- /formal-version/servers/s_NRF_h0.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import json 3 | import threading 4 | import socket 5 | 6 | from h2.connection import H2Connection 7 | from h2.events import RequestReceived, DataReceived 8 | from hyper import HTTP20Connection 9 | 10 | # Test Mode: Listen: localhost:9007 11 | # Otherwise: Listen: 10.0.3.1:8080 12 | TEST_MODE = True if len(sys.argv) == 2 and sys.argv[1] == '--test' else False 13 | LISTEN_PORT = 9007 if TEST_MODE else 8080 14 | 15 | # SBA Entity Running Mode: FAST, REGULAR, WAITABLE 16 | 17 | LOCK = threading.Lock() 18 | 19 | 20 | class SBANRFConnection(object): 21 | "An object of simple HTTP/2 connection" 22 | 23 | def __init__(self, sock, TEST_MODE, lock): 24 | self.sock = sock 25 | self.TEST_MODE = TEST_MODE 26 | self.lock = lock 27 | self.conn = H2Connection(client_side=False) 28 | 29 | # Space for incoming request headers 30 | self.rx_headers = False 31 | self.rx_body = False 32 | self.stream_id = False 33 | 34 | self.rx_config = 'REGULAR' # Entity comsuming mode from header 35 | self.pkt_rlt = False # Entity comsuming result 36 | self.fw_body = {} # Body for fowarding 37 | 38 | def run_forever(self): 39 | self.conn.initiate_connection() 40 | self.sock.sendall(self.conn.data_to_send()) 41 | 42 | while True: 43 | data = self.sock.recv(65535) 44 | if not data: 45 | break 46 | 47 | events = self.conn.receive_data(data) 48 | 49 | for event in events: 50 | if isinstance(event, RequestReceived): 51 | self.rx_headers = event.headers 52 | self.stream_id = event.stream_id 53 | elif isinstance(event, DataReceived): 54 | self.rx_body = event.data 55 | 56 | # Foward request, wait for its response, then send response to where this request from 57 | if self.rx_headers and self.rx_body: 58 | self.send_response() 59 | self.resource_providing() 60 | if self.fw_body != {}: 61 | self.foward_request() 62 | else: 63 | print('Fowarding Failed.') 64 | 65 | data_to_send = self.conn.data_to_send() 66 | if data_to_send: 67 | self.sock.sendall(data_to_send) 68 | 69 | def resource_providing(self): 70 | # Parsing Request Body 71 | body_json = json.loads(self.rx_body) 72 | print(body_json) 73 | self.rx_config = str(body_json['MODE']['NRF']) 74 | self.fw_body = { 75 | 'RESULT': body_json['RESULT'] 76 | } 77 | ents = [str(x) for x in body_json['SBA_ENTITY']] 78 | ents.pop(0) # delete NRF in entities list 79 | confs = {str(k): str(v) for k, v in body_json['MODE'].items()} 80 | confs.pop('NRF', None) # delete NRF in config table 81 | 82 | # Fill into fowarding body 83 | self.fw_body.setdefault('SBA_ENTITY', []) 84 | self.fw_body.setdefault('MODE', {}) 85 | self.fw_body.setdefault('RESULT', {}) 86 | self.fw_body['SBA_ENTITY'] = ents 87 | self.fw_body['MODE'] = confs 88 | self.fw_body['RESULT']['NRF'] = True # Always gives True for testing 89 | self.lock.acquire() 90 | print('Recieved Packet.\nMode: {}'.format(self.rx_config)) 91 | print('RX Header: {}'.format(self.rx_headers)) 92 | print('RX Body: {}'.format(body_json)) 93 | print('==========RX') 94 | self.lock.release() 95 | 96 | def send_response(self): 97 | body = json.dumps( 98 | {'Content': 'Recieved by SBAES - NRF'}).encode('utf-8') 99 | self.conn.send_headers( 100 | stream_id=self.stream_id, 101 | headers=[ 102 | (':status', '200'), 103 | ('server', 's_NRF-h2-server/1.0'), 104 | ('content-length', str(len(body))), 105 | ('content-type', 'application/json'), 106 | ('id', str(dict(self.rx_headers)['id'])) 107 | ], 108 | ) 109 | self.conn.send_data( 110 | stream_id=self.stream_id, 111 | data=body, 112 | end_stream=True 113 | ) 114 | 115 | def foward_request(self): 116 | fw_table = { 117 | 'NRF': 'localhost:9007', 118 | 'AUSF': 'localhost:9008', 119 | 'UDM': 'localhost:9009', 120 | 'AMF': 'localhost:9010', 121 | 'SMF': 'localhost:9011', 122 | 'PCF': 'localhost:9012', 123 | 'AF': 'localhost:9013' 124 | } if self.TEST_MODE else { 125 | 'NRF': '10.0.3.1:8080', 126 | 'AUSF': '10.0.3.2:8080', 127 | 'UDM': '10.0.3.3:8080', 128 | 'AMF': '10.0.3.4:8080', 129 | 'SMF': '10.0.3.5:8080', 130 | 'PCF': '10.0.3.6:8080', 131 | 'AF': '10.0.3.7:8080' 132 | } 133 | next_ent = self.fw_body['SBA_ENTITY'][0] 134 | print('Fowarded packet to SBA Entity {} at http://{}'.format(next_ent, 135 | fw_table[next_ent])) # Next SBA Entity to foward to 136 | send_conn = HTTP20Connection(fw_table[next_ent]) 137 | fw_body = json.dumps(self.fw_body).encode('utf-8') 138 | send_conn.request( 139 | 'POST', '/', headers=dict(self.rx_headers), body=fw_body) 140 | resp = send_conn.get_response() 141 | if resp: 142 | self.lock.acquire() 143 | print('Fowarded packet to SBA Entity {} at http://{}'.format(next_ent, fw_table[next_ent])) 144 | self.res_body = resp.read() 145 | print('FW Header: {}'.format(dict(self.rx_headers))) 146 | print('FW Body: {}'.format(fw_body)) 147 | print('Response: {}'.format(self.res_body)) 148 | print('==========FW') 149 | self.lock.release() 150 | 151 | 152 | print('SBA Entity NRF server started at http://{}:{}'.format( 153 | '0.0.0.0' if TEST_MODE else '10.0.3.1', LISTEN_PORT)) 154 | 155 | sock = socket.socket() 156 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 157 | sock.bind(('0.0.0.0', int(LISTEN_PORT))) 158 | sock.listen(5) 159 | 160 | while True: 161 | try: 162 | connection = SBANRFConnection(sock.accept()[0], TEST_MODE, LOCK) 163 | th = threading.Thread(target=connection.run_forever) 164 | th.start() 165 | except(SystemExit, KeyboardInterrupt): 166 | break 167 | -------------------------------------------------------------------------------- /formal-version/servers/s_PCF_h0.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import json 3 | import threading 4 | import socket 5 | 6 | from h2.connection import H2Connection 7 | from h2.events import RequestReceived, DataReceived 8 | from hyper import HTTP20Connection 9 | 10 | # Test Mode: Listen: localhost:9012 11 | # Otherwise: Listen: 10.0.3.6:8080 12 | TEST_MODE = True if len(sys.argv) == 2 and sys.argv[1] == '--test' else False 13 | LISTEN_PORT = 9012 if TEST_MODE else 8080 14 | 15 | # SBA Entity Running Mode: FAST, REGULAR, WAITABLE 16 | 17 | LOCK = threading.Lock() 18 | 19 | 20 | class SBAPCFConnection(object): 21 | "An object of simple HTTP/2 connection" 22 | 23 | def __init__(self, sock, TEST_MODE, lock): 24 | self.sock = sock 25 | self.TEST_MODE = TEST_MODE 26 | self.lock = lock 27 | self.conn = H2Connection(client_side=False) 28 | 29 | # Space for incoming request headers 30 | self.rx_headers = False 31 | self.rx_body = False 32 | self.stream_id = False 33 | 34 | self.rx_config = 'REGULAR' # Entity comsuming mode from header 35 | self.pkt_rlt = False # Entity comsuming result 36 | self.fw_body = {} # Body for fowarding 37 | 38 | def run_forever(self): 39 | self.conn.initiate_connection() 40 | self.sock.sendall(self.conn.data_to_send()) 41 | 42 | while True: 43 | data = self.sock.recv(65535) 44 | if not data: 45 | break 46 | 47 | events = self.conn.receive_data(data) 48 | 49 | for event in events: 50 | if isinstance(event, RequestReceived): 51 | self.rx_headers = event.headers 52 | self.stream_id = event.stream_id 53 | elif isinstance(event, DataReceived): 54 | self.rx_body = event.data 55 | 56 | # Foward request, wait for its response, then send response to where this request from 57 | if self.rx_headers and self.rx_body: 58 | self.send_response() 59 | self.resource_providing() 60 | if self.fw_body != {}: 61 | self.foward_request() 62 | else: 63 | print('Fowarding Failed.') 64 | 65 | data_to_send = self.conn.data_to_send() 66 | if data_to_send: 67 | self.sock.sendall(data_to_send) 68 | 69 | def resource_providing(self): 70 | # Parsing Request Body 71 | body_json = json.loads(self.rx_body) 72 | print(body_json) 73 | self.rx_config = str(body_json['MODE']['PCF']) 74 | self.fw_body = { 75 | 'RESULT': body_json['RESULT'] 76 | } 77 | ents = [str(x) for x in body_json['SBA_ENTITY']] 78 | ents.pop(0) # delete PCF in entities list 79 | confs = {str(k): str(v) for k, v in body_json['MODE'].items()} 80 | confs.pop('PCF', None) # delete PCF in config table 81 | 82 | # Fill into fowarding body 83 | self.fw_body.setdefault('SBA_ENTITY', []) 84 | self.fw_body.setdefault('MODE', {}) 85 | self.fw_body.setdefault('RESULT', {}) 86 | self.fw_body['SBA_ENTITY'] = ents 87 | self.fw_body['MODE'] = confs 88 | self.fw_body['RESULT']['PCF'] = True # Always gives True for testing 89 | self.lock.acquire() 90 | print('Recieved Packet.\nMode: {}'.format(self.rx_config)) 91 | print('RX Header: {}'.format(self.rx_headers)) 92 | print('RX Body: {}'.format(body_json)) 93 | print('==========RX') 94 | self.lock.release() 95 | 96 | def send_response(self): 97 | body = json.dumps( 98 | {'Content': 'Recieved by SBAES - PCF'}).encode('utf-8') 99 | self.conn.send_headers( 100 | stream_id=self.stream_id, 101 | headers=[ 102 | (':status', '200'), 103 | ('server', 's_PCF-h2-server/1.0'), 104 | ('content-length', str(len(body))), 105 | ('content-type', 'application/json'), 106 | ('id', str(dict(self.rx_headers)['id'])) 107 | ], 108 | ) 109 | self.conn.send_data( 110 | stream_id=self.stream_id, 111 | data=body, 112 | end_stream=True 113 | ) 114 | 115 | def foward_request(self): 116 | fw_table = { 117 | 'NRF': 'localhost:9007', 118 | 'AUSF': 'localhost:9008', 119 | 'UDM': 'localhost:9009', 120 | 'AMF': 'localhost:9010', 121 | 'SMF': 'localhost:9011', 122 | 'PCF': 'localhost:9012', 123 | 'AF': 'localhost:9013' 124 | } if self.TEST_MODE else { 125 | 'NRF': '10.0.3.1:8080', 126 | 'AUSF': '10.0.3.2:8080', 127 | 'UDM': '10.0.3.3:8080', 128 | 'AMF': '10.0.3.4:8080', 129 | 'SMF': '10.0.3.5:8080', 130 | 'PCF': '10.0.3.6:8080', 131 | 'AF': '10.0.3.7:8080' 132 | } 133 | next_ent = self.fw_body['SBA_ENTITY'][0] 134 | print('Fowarded packet to SBA Entity {} at http://{}'.format(next_ent, 135 | fw_table[next_ent])) # Next SBA Entity to foward to 136 | send_conn = HTTP20Connection(fw_table[next_ent]) 137 | fw_body = json.dumps(self.fw_body).encode('utf-8') 138 | send_conn.request( 139 | 'POST', '/', headers=dict(self.rx_headers), body=fw_body) 140 | resp = send_conn.get_response() 141 | if resp: 142 | self.lock.acquire() 143 | print('Fowarded packet to SBA Entity {} at http://{}'.format(next_ent, fw_table[next_ent])) 144 | self.res_body = resp.read() 145 | print('FW Header: {}'.format(dict(self.rx_headers))) 146 | print('FW Body: {}'.format(fw_body)) 147 | print('Response: {}'.format(self.res_body)) 148 | print('==========FW') 149 | self.lock.release() 150 | 151 | 152 | print('SBA Entity PCF server started at http://{}:{}'.format( 153 | '0.0.0.0' if TEST_MODE else '10.0.3.6', LISTEN_PORT)) 154 | 155 | sock = socket.socket() 156 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 157 | sock.bind(('0.0.0.0', int(LISTEN_PORT))) 158 | sock.listen(5) 159 | 160 | while True: 161 | try: 162 | connection = SBAPCFConnection(sock.accept()[0], TEST_MODE, LOCK) 163 | th = threading.Thread(target=connection.run_forever) 164 | th.start() 165 | except(SystemExit, KeyboardInterrupt): 166 | break 167 | -------------------------------------------------------------------------------- /formal-version/servers/s_SMF_h0.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import json 3 | import threading 4 | import socket 5 | 6 | from h2.connection import H2Connection 7 | from h2.events import RequestReceived, DataReceived 8 | from hyper import HTTP20Connection 9 | 10 | # Test Mode: Listen: localhost:9011 11 | # Otherwise: Listen: 10.0.3.5:8080 12 | TEST_MODE = True if len(sys.argv) == 2 and sys.argv[1] == '--test' else False 13 | LISTEN_PORT = 9011 if TEST_MODE else 8080 14 | 15 | # SBA Entity Running Mode: FAST, REGULAR, WAITABLE 16 | 17 | LOCK = threading.Lock() 18 | 19 | 20 | class SBASMFConnection(object): 21 | "An object of simple HTTP/2 connection" 22 | 23 | def __init__(self, sock, TEST_MODE, lock): 24 | self.sock = sock 25 | self.TEST_MODE = TEST_MODE 26 | self.lock = lock 27 | self.conn = H2Connection(client_side=False) 28 | 29 | # Space for incoming request headers 30 | self.rx_headers = False 31 | self.rx_body = False 32 | self.stream_id = False 33 | 34 | self.rx_config = 'REGULAR' # Entity comsuming mode from header 35 | self.pkt_rlt = False # Entity comsuming result 36 | self.fw_body = {} # Body for fowarding 37 | 38 | def run_forever(self): 39 | self.conn.initiate_connection() 40 | self.sock.sendall(self.conn.data_to_send()) 41 | 42 | while True: 43 | data = self.sock.recv(65535) 44 | if not data: 45 | break 46 | 47 | events = self.conn.receive_data(data) 48 | 49 | for event in events: 50 | if isinstance(event, RequestReceived): 51 | self.rx_headers = event.headers 52 | self.stream_id = event.stream_id 53 | elif isinstance(event, DataReceived): 54 | self.rx_body = event.data 55 | 56 | # Foward request, wait for its response, then send response to where this request from 57 | if self.rx_headers and self.rx_body: 58 | self.send_response() 59 | self.resource_providing() 60 | if self.fw_body != {}: 61 | self.foward_request() 62 | else: 63 | print('Fowarding Failed.') 64 | 65 | data_to_send = self.conn.data_to_send() 66 | if data_to_send: 67 | self.sock.sendall(data_to_send) 68 | 69 | def resource_providing(self): 70 | # Parsing Request Body 71 | body_json = json.loads(self.rx_body) 72 | print(body_json) 73 | self.rx_config = str(body_json['MODE']['SMF']) 74 | self.fw_body = { 75 | 'RESULT': body_json['RESULT'] 76 | } 77 | 78 | # Fill into fowarding body 79 | self.fw_body.setdefault('RESULT', {}) 80 | self.fw_body['RESULT']['SMF'] = True # Always gives True for testing 81 | self.lock.acquire() 82 | print('Recieved Packet.\nMode: {}'.format(self.rx_config)) 83 | print('RX Header: {}'.format(self.rx_headers)) 84 | print('RX Body: {}'.format(body_json)) 85 | print('==========RX') 86 | self.lock.release() 87 | 88 | def send_response(self): 89 | body = json.dumps( 90 | {'Content': 'Recieved by SBAES - SMF'}).encode('utf-8') 91 | self.conn.send_headers( 92 | stream_id=self.stream_id, 93 | headers=[ 94 | (':status', '200'), 95 | ('server', 's_SMF-h2-server/1.0'), 96 | ('content-length', str(len(body))), 97 | ('content-type', 'application/json'), 98 | ('id', str(dict(self.rx_headers)['id'])) 99 | ], 100 | ) 101 | self.conn.send_data( 102 | stream_id=self.stream_id, 103 | data=body, 104 | end_stream=True 105 | ) 106 | 107 | def foward_request(self): 108 | fw_table = 'localhost:9002' if self.TEST_MODE else '10.0.4.1:8080' 109 | 110 | send_conn = HTTP20Connection(fw_table) 111 | fw_body = json.dumps(self.fw_body).encode('utf-8') 112 | fw_header = dict(self.rx_headers) 113 | fw_header['plane'] = 'control' 114 | send_conn.request('POST', '/', headers=fw_header, body=fw_body) 115 | resp = send_conn.get_response() 116 | if resp: 117 | self.lock.acquire() 118 | print('Fowarded packet to UPF at http://{}'.format(fw_table)) 119 | self.res_body = resp.read() 120 | print('FW Header: {}'.format(dict(self.rx_headers))) 121 | print('FW Body: {}'.format(fw_body)) 122 | print('Response: {}'.format(self.res_body)) 123 | print('==========FW') 124 | self.lock.release() 125 | 126 | 127 | print('SBA Entity SMF server started at http://{}:{}'.format( 128 | '0.0.0.0' if TEST_MODE else '10.0.3.5', LISTEN_PORT)) 129 | 130 | sock = socket.socket() 131 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 132 | sock.bind(('0.0.0.0', int(LISTEN_PORT))) 133 | sock.listen(5) 134 | 135 | while True: 136 | try: 137 | connection = SBASMFConnection(sock.accept()[0], TEST_MODE, LOCK) 138 | th = threading.Thread(target=connection.run_forever) 139 | th.start() 140 | except(SystemExit, KeyboardInterrupt): 141 | break 142 | -------------------------------------------------------------------------------- /formal-version/servers/s_UDM_h0.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import json 3 | import threading 4 | import socket 5 | 6 | from h2.connection import H2Connection 7 | from h2.events import RequestReceived, DataReceived 8 | from hyper import HTTP20Connection 9 | 10 | # Test Mode: Listen: localhost:9009 11 | # Otherwise: Listen: 10.0.3.3:8080 12 | TEST_MODE = True if len(sys.argv) == 2 and sys.argv[1] == '--test' else False 13 | LISTEN_PORT = 9009 if TEST_MODE else 8080 14 | 15 | # SBA Entity Running Mode: FAST, REGULAR, WAITABLE 16 | 17 | LOCK = threading.Lock() 18 | 19 | 20 | class SBAUDMConnection(object): 21 | "An object of simple HTTP/2 connection" 22 | 23 | def __init__(self, sock, TEST_MODE, lock): 24 | self.sock = sock 25 | self.TEST_MODE = TEST_MODE 26 | self.lock = lock 27 | self.conn = H2Connection(client_side=False) 28 | 29 | # Space for incoming request headers 30 | self.rx_headers = False 31 | self.rx_body = False 32 | self.stream_id = False 33 | 34 | self.rx_config = 'REGULAR' # Entity comsuming mode from header 35 | self.pkt_rlt = False # Entity comsuming result 36 | self.fw_body = {} # Body for fowarding 37 | 38 | def run_forever(self): 39 | self.conn.initiate_connection() 40 | self.sock.sendall(self.conn.data_to_send()) 41 | 42 | while True: 43 | data = self.sock.recv(65535) 44 | if not data: 45 | break 46 | 47 | events = self.conn.receive_data(data) 48 | 49 | for event in events: 50 | if isinstance(event, RequestReceived): 51 | self.rx_headers = event.headers 52 | self.stream_id = event.stream_id 53 | elif isinstance(event, DataReceived): 54 | self.rx_body = event.data 55 | 56 | # Foward request, wait for its response, then send response to where this request from 57 | if self.rx_headers and self.rx_body: 58 | self.send_response() 59 | self.resource_providing() 60 | if self.fw_body != {}: 61 | self.foward_request() 62 | else: 63 | print('Fowarding Failed.') 64 | 65 | data_to_send = self.conn.data_to_send() 66 | if data_to_send: 67 | self.sock.sendall(data_to_send) 68 | 69 | def resource_providing(self): 70 | # Parsing Request Body 71 | body_json = json.loads(self.rx_body) 72 | print(body_json) 73 | self.rx_config = str(body_json['MODE']['UDM']) 74 | self.fw_body = { 75 | 'RESULT': body_json['RESULT'] 76 | } 77 | ents = [str(x) for x in body_json['SBA_ENTITY']] 78 | ents.pop(0) # delete UDM in entities list 79 | confs = {str(k): str(v) for k, v in body_json['MODE'].items()} 80 | confs.pop('UDM', None) # delete UDM in config table 81 | 82 | # Fill into fowarding body 83 | self.fw_body.setdefault('SBA_ENTITY', []) 84 | self.fw_body.setdefault('MODE', {}) 85 | self.fw_body.setdefault('RESULT', {}) 86 | self.fw_body['SBA_ENTITY'] = ents 87 | self.fw_body['MODE'] = confs 88 | self.fw_body['RESULT']['UDM'] = True # Always gives True for testing 89 | self.lock.acquire() 90 | print('Recieved Packet.\nMode: {}'.format(self.rx_config)) 91 | print('RX Header: {}'.format(self.rx_headers)) 92 | print('RX Body: {}'.format(body_json)) 93 | print('==========RX') 94 | self.lock.release() 95 | 96 | def send_response(self): 97 | body = json.dumps( 98 | {'Content': 'Recieved by SBAES - UDM'}).encode('utf-8') 99 | self.conn.send_headers( 100 | stream_id=self.stream_id, 101 | headers=[ 102 | (':status', '200'), 103 | ('server', 's_UDM-h2-server/1.0'), 104 | ('content-length', str(len(body))), 105 | ('content-type', 'application/json'), 106 | ('id', str(dict(self.rx_headers)['id'])) 107 | ], 108 | ) 109 | self.conn.send_data( 110 | stream_id=self.stream_id, 111 | data=body, 112 | end_stream=True 113 | ) 114 | 115 | def foward_request(self): 116 | fw_table = { 117 | 'NRF': 'localhost:9007', 118 | 'AUSF': 'localhost:9008', 119 | 'UDM': 'localhost:9009', 120 | 'AMF': 'localhost:9010', 121 | 'SMF': 'localhost:9011', 122 | 'PCF': 'localhost:9012', 123 | 'AF': 'localhost:9013' 124 | } if self.TEST_MODE else { 125 | 'NRF': '10.0.3.1:8080', 126 | 'AUSF': '10.0.3.2:8080', 127 | 'UDM': '10.0.3.3:8080', 128 | 'AMF': '10.0.3.4:8080', 129 | 'SMF': '10.0.3.5:8080', 130 | 'PCF': '10.0.3.6:8080', 131 | 'AF': '10.0.3.7:8080' 132 | } 133 | next_ent = self.fw_body['SBA_ENTITY'][0] 134 | print('Fowarded packet to SBA Entity {} at http://{}'.format(next_ent, 135 | fw_table[next_ent])) # Next SBA Entity to foward to 136 | send_conn = HTTP20Connection(fw_table[next_ent]) 137 | fw_body = json.dumps(self.fw_body).encode('utf-8') 138 | send_conn.request( 139 | 'POST', '/', headers=dict(self.rx_headers), body=fw_body) 140 | resp = send_conn.get_response() 141 | if resp: 142 | self.lock.acquire() 143 | print('Fowarded packet to SBA Entity {} at http://{}'.format(next_ent, fw_table[next_ent])) 144 | self.res_body = resp.read() 145 | print('FW Header: {}'.format(dict(self.rx_headers))) 146 | print('FW Body: {}'.format(fw_body)) 147 | print('Response: {}'.format(self.res_body)) 148 | print('==========FW') 149 | self.lock.release() 150 | 151 | 152 | print('SBA Entity AMF server started at http://{}:{}'.format( 153 | '0.0.0.0' if TEST_MODE else '10.0.3.3', LISTEN_PORT)) 154 | 155 | sock = socket.socket() 156 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 157 | sock.bind(('0.0.0.0', int(LISTEN_PORT))) 158 | sock.listen(5) 159 | 160 | while True: 161 | try: 162 | connection = SBAUDMConnection(sock.accept()[0], TEST_MODE, LOCK) 163 | th = threading.Thread(target=connection.run_forever) 164 | th.start() 165 | except(SystemExit, KeyboardInterrupt): 166 | break 167 | -------------------------------------------------------------------------------- /formal-version/servers/uam_h0.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import threading 3 | import socket 4 | 5 | from h2.connection import H2Connection 6 | from h2.events import RequestReceived, DataReceived 7 | from hyper import HTTP20Connection 8 | 9 | # Test Mode: Listen: localhost:9001 10 | # Data Plane: localhost:9002 11 | # Control Plane: localhost:9004,9005,9006 12 | # Otherwise: Listen: 10.0.1.1:8080 13 | # Data Plane: 10.0.4.1:8080 14 | # Control Plane: 10.0.2.1,2,3:8080 15 | TEST_MODE = True if len(sys.argv) == 2 and sys.argv[1] == '--test' else False 16 | LISTEN_PORT = 9001 if TEST_MODE else 8080 17 | 18 | LOCK = threading.Lock() 19 | 20 | 21 | class UAMConnection(object): 22 | "An object of simple HTTP/2 connection" 23 | 24 | def __init__(self, sock, TEST_MODE, lock): 25 | self.sock = sock 26 | self.TEST_MODE = TEST_MODE 27 | self.lock = lock 28 | self.conn = H2Connection(client_side=False) 29 | 30 | # Packet datas 31 | self.rx_headers = False 32 | self.rx_body = False 33 | self.rx_scenario = False 34 | self.stream_id = False 35 | self.res_rxts = False # rx-timestamp from data network 36 | 37 | def run_forever(self): 38 | self.conn.initiate_connection() 39 | self.sock.sendall(self.conn.data_to_send()) 40 | 41 | while True: 42 | data = self.sock.recv(65535) 43 | if not data: 44 | break 45 | 46 | events = self.conn.receive_data(data) 47 | 48 | for event in events: 49 | if isinstance(event, RequestReceived): 50 | self.rx_headers = event.headers 51 | self.rx_scenario = str(dict(self.rx_headers)['scenario']) 52 | self.stream_id = event.stream_id 53 | elif isinstance(event, DataReceived): 54 | self.rx_body = event.data 55 | 56 | # Foward request, wait for its response, then send response to where this request from 57 | if self.rx_headers and self.rx_body and self.rx_scenario: 58 | self.foward_data_plane_packet() 59 | self.send_control_plane_packet() 60 | self.send_response() 61 | 62 | data_to_send = self.conn.data_to_send() 63 | if data_to_send: 64 | self.sock.sendall(data_to_send) 65 | 66 | def send_response(self): 67 | self.conn.send_headers( 68 | stream_id=self.stream_id, 69 | headers=[ 70 | (':status', '200'), 71 | ('server', 'dp_DN-h2-server/1.0'), 72 | ('content-length', str(len(self.res_body))), 73 | ('content-type', 'application/json'), 74 | ('rx-timestamp', self.res_rxts) 75 | ], 76 | ) 77 | self.conn.send_data( 78 | stream_id=self.stream_id, 79 | data=self.res_body, 80 | end_stream=True 81 | ) 82 | 83 | def send_control_plane_packet(self): 84 | "Generate a control plane packet and send to NFV Services" 85 | ip = { 86 | 'URLLC': 'localhost:9004', 87 | 'eMBB': 'localhost:9005', 88 | 'mMTC': 'localhost:9006' 89 | } if self.TEST_MODE else { 90 | 'URLLC': '10.0.2.1:8080', 91 | 'eMBB': '10.0.2.2:8080', 92 | 'mMTC': '10.0.2.3:8080' 93 | } 94 | scenario = self.rx_scenario 95 | send_headers = { 96 | 'id': str(dict(self.rx_headers)['id']) 97 | } 98 | send_conn = HTTP20Connection(ip[scenario]) 99 | send_conn.request('GET', '/', headers=send_headers) 100 | resp = send_conn.get_response() 101 | if resp: 102 | self.lock.acquire() 103 | print('Sent control plane packet to NFV {} Service at {}'.format(scenario, ip[scenario])) 104 | print('CP FW Header: {}'.format(send_headers)) 105 | print('Response: {}'.format(resp.read())) 106 | print('==========CP-FW') 107 | self.lock.release() 108 | 109 | def foward_data_plane_packet(self): 110 | "Duplicate a data plane packet and send to UPF" 111 | upf_ip = 'localhost:9002' if self.TEST_MODE else '10.0.4.1:8080' 112 | fw_headers = { 113 | 'content-length': str(len(self.rx_body)), 114 | 'content-type': 'application/json', 115 | 'id': str(dict(self.rx_headers)['id']), 116 | 'plane': 'user' 117 | } 118 | send_conn = HTTP20Connection('{}'.format(upf_ip)) 119 | send_conn.request('POST', '/', headers=fw_headers, body=self.rx_body) 120 | resp = send_conn.get_response() 121 | if resp: 122 | self.lock.acquire() 123 | print('Fowarded User Plane packet to UPF') 124 | print('UP FW Header: {}'.format(fw_headers)) 125 | print('UP FW Body: {}'.format(self.rx_body)) 126 | self.res_body = resp.read() 127 | print('Response: {}'.format(self.res_body)) 128 | self.res_rxts = resp.headers['rx-timestamp'][0] 129 | print('==========UP-FW') 130 | self.lock.release() 131 | 132 | 133 | print('UAM server started at http://{}:{}'.format('0.0.0.0' if TEST_MODE else '10.0.1.1', LISTEN_PORT)) 134 | print('Packets will foward to {}'.format('test server' if TEST_MODE else 'NFVSM')) 135 | 136 | sock = socket.socket() 137 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 138 | sock.bind(('0.0.0.0', int(LISTEN_PORT))) 139 | sock.listen(5) 140 | 141 | while True: 142 | try: 143 | connection = UAMConnection(sock.accept()[0], TEST_MODE, LOCK) 144 | th = threading.Thread(target=connection.run_forever) 145 | th.start() 146 | except(SystemExit, KeyboardInterrupt): 147 | break 148 | -------------------------------------------------------------------------------- /formal-version/servers/ue_URLLC_h.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import json 3 | import time 4 | import hashlib 5 | import threading 6 | 7 | from hyper import HTTP20Connection 8 | 9 | # Test Mode: Send to localhost:9001 10 | # Otherwise: Send to 10.0.1.1:8080 11 | TEST_MODE = True if len(sys.argv) == 2 and sys.argv[1] == '--test' else False 12 | HOST = 'localhost' if TEST_MODE else '10.0.1.1' 13 | SEND_PORT = 9001 if TEST_MODE else 8080 14 | 15 | pkt_cnt = 1 16 | pkt_per_s = 1 17 | expr_time = 1 18 | 19 | data = { 20 | 'Content': 'NCCUCS mclab testing' 21 | } 22 | transfer_data = json.dumps(data).encode('utf-8') 23 | headers = { 24 | 'content-length': str(len(transfer_data)), 25 | 'content-type': 'application/json', 26 | 'scenario': 'URLLC' 27 | } 28 | 29 | 30 | def send_packet(pkt_cnt): 31 | print('Sending URLLC packet {:0>4d} into system\nheaders: {}'.format(pkt_cnt, headers)) 32 | conn = HTTP20Connection('{}:{}'.format(HOST, SEND_PORT)) 33 | 34 | # Add SHA256 encrypted id to header i.e. sha256('URLLC-PKT-0132') 35 | headers['id'] = hashlib.sha256('URLLC-PKT-{:0>4d}'.format(pkt_cnt)).hexdigest() 36 | # headers['id'] = 'URLLC-PKT-{:0>4d}'.format(pkt_cnt) 37 | 38 | TX_TP = time.time().real 39 | conn.request('POST', '/', headers=headers, body=transfer_data) 40 | 41 | resp = conn.get_response() 42 | RES_TP = time.time().real 43 | RX_TP = float(resp.headers['rx-timestamp'][0]) 44 | print('Response of URLLC packet {:0>4d}:'.format(pkt_cnt)) 45 | print(json.dumps(dict(resp.headers))) 46 | print(resp.read()) 47 | print('TX - {:.6f} | RX - {:.6f} | RES - {:.6f}'.format(TX_TP, RX_TP, RES_TP)) 48 | print('Transfer Time - {}ms | RTT - {}ms'.format(round((RX_TP - TX_TP) * 1000, 1), round((RES_TP - TX_TP) * 1000, 1))) 49 | print('-------------') 50 | # print('System Works!') 51 | 52 | pkt_cnt += 1 53 | 54 | 55 | while pkt_cnt <= pkt_per_s * expr_time: 56 | th = threading.Thread(target=send_packet, args=(pkt_cnt,)) 57 | th.start() 58 | 59 | pkt_cnt += 1 60 | time.sleep(1 / pkt_per_s) 61 | -------------------------------------------------------------------------------- /formal-version/servers/ue_eMBB_h.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import json 3 | import time 4 | import hashlib 5 | import threading 6 | 7 | from hyper import HTTP20Connection 8 | 9 | # Test Mode: Send to localhost:9001 10 | # Otherwise: Send to 10.0.1.1:8080 11 | TEST_MODE = True if len(sys.argv) == 2 and sys.argv[1] == '--test' else False 12 | HOST = 'localhost' if TEST_MODE else '10.0.1.1' 13 | SEND_PORT = 9001 if TEST_MODE else 8080 14 | 15 | pkt_cnt = 1 16 | pkt_per_s = 200 17 | expr_time = 1 18 | 19 | data = { 20 | 'Content {}'.format(x): 'NCCUCS mclab testing {}'.format(x) for x in range(1, 51) 21 | } 22 | transfer_data = json.dumps(data).encode('utf-8') 23 | headers = { 24 | 'content-length': str(len(transfer_data)), 25 | 'content-type': 'application/json', 26 | 'scenario': 'eMBB' 27 | } 28 | 29 | 30 | def send_packet(pkt_cnt): 31 | print('Sending eMBB packet {:0>4d} into system\nheaders: {}'.format(pkt_cnt, headers)) 32 | conn = HTTP20Connection('{}:{}'.format(HOST, SEND_PORT)) 33 | 34 | # Add SHA256 encrypted id to header i.e. sha256('eMBB-PKT-0132') 35 | headers['id'] = hashlib.sha256('eMBB-PKT-{:0>4d}'.format(pkt_cnt)).hexdigest() 36 | # headers['id'] = 'eMBB-PKT-{:0>4d}'.format(pkt_cnt) 37 | 38 | TX_TP = time.time().real 39 | conn.request('POST', '/', headers=headers, body=transfer_data) 40 | 41 | resp = conn.get_response() 42 | RES_TP = time.time().real 43 | RX_TP = float(resp.headers['rx-timestamp'][0]) 44 | print('Response of eMBB packet {:0>4d}:'.format(pkt_cnt)) 45 | print(json.dumps(dict(resp.headers))) 46 | print(resp.read()) 47 | print('TX - {:.6f} | RX - {:.6f} | RES - {:.6f}'.format(TX_TP, RX_TP, RES_TP)) 48 | print('Transfer Time - {}ms | RTT - {}ms'.format(round((RX_TP - TX_TP) * 1000, 1), round((RES_TP - TX_TP) * 1000, 1))) 49 | print('-------------') 50 | # print('System Works!') 51 | 52 | pkt_cnt += 1 53 | 54 | 55 | while pkt_cnt <= pkt_per_s * expr_time: 56 | th = threading.Thread(target=send_packet, args=(pkt_cnt,)) 57 | th.start() 58 | 59 | pkt_cnt += 1 60 | time.sleep(1 / pkt_per_s) 61 | -------------------------------------------------------------------------------- /formal-version/servers/ue_mMTC_h.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import json 3 | import time 4 | import hashlib 5 | import threading 6 | 7 | from hyper import HTTP20Connection 8 | 9 | # Test Mode: Send to localhost:9001 10 | # Otherwise: Send to 10.0.1.1:8080 11 | TEST_MODE = True if len(sys.argv) == 2 and sys.argv[1] == '--test' else False 12 | HOST = 'localhost' if TEST_MODE else '10.0.1.1' 13 | SEND_PORT = 9001 if TEST_MODE else 8080 14 | 15 | pkt_cnt = 1 16 | pkt_per_s = 450 17 | expr_time = 1 18 | 19 | data = { 20 | 'Content': 'NCCUCS mclab testing' 21 | } 22 | transfer_data = json.dumps(data).encode('utf-8') 23 | headers = { 24 | 'content-length': str(len(transfer_data)), 25 | 'content-type': 'application/json', 26 | 'scenario': 'mMTC' 27 | } 28 | 29 | 30 | def send_packet(pkt_cnt): 31 | print('Sending mMTC packet {:0>4d} into system\nheaders: {}'.format(pkt_cnt, headers)) 32 | conn = HTTP20Connection('{}:{}'.format(HOST, SEND_PORT)) 33 | 34 | # Add SHA256 encrypted id to header i.e. sha256('mMTC-PKT-0132') 35 | headers['id'] = hashlib.sha256('mMTC-PKT-{:0>4d}'.format(pkt_cnt)).hexdigest() 36 | # headers['id'] = 'mMTC-PKT-{:0>4d}'.format(pkt_cnt) 37 | 38 | TX_TP = time.time().real 39 | conn.request('POST', '/', headers=headers, body=transfer_data) 40 | 41 | resp = conn.get_response() 42 | RES_TP = time.time().real 43 | RX_TP = float(resp.headers['rx-timestamp'][0]) 44 | print('Response of mMTC packet {:0>4d}:'.format(pkt_cnt)) 45 | print(json.dumps(dict(resp.headers))) 46 | print(resp.read()) 47 | print('TX - {:.6f} | RX - {:.6f} | RES - {:.6f}'.format(TX_TP, RX_TP, RES_TP)) 48 | print('Transfer Time - {}ms | RTT - {}ms'.format(round((RX_TP - TX_TP) * 1000, 1), round((RES_TP - TX_TP) * 1000, 1))) 49 | print('-------------') 50 | # print('System Works!') 51 | 52 | pkt_cnt += 1 53 | 54 | 55 | while pkt_cnt <= pkt_per_s * expr_time: 56 | th = threading.Thread(target=send_packet, args=(pkt_cnt,)) 57 | th.start() 58 | 59 | pkt_cnt += 1 60 | time.sleep(1 / pkt_per_s) 61 | -------------------------------------------------------------------------------- /formal-version/ue-access-ctrl.py: -------------------------------------------------------------------------------- 1 | from ryu.base import app_manager 2 | from ryu.controller import ofp_event 3 | from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER 4 | from ryu.controller.handler import set_ev_cls 5 | from ryu.ofproto import ofproto_v1_3 6 | from ryu.lib.packet import packet 7 | from ryu.lib.packet import ethernet, ether_types, arp 8 | 9 | # REST Api Packages 10 | import json 11 | import logging 12 | from ryu.app.wsgi import WSGIApplication, ControllerBase, route 13 | from webob import Response 14 | 15 | ue_instance_name = 'UE' 16 | 17 | 18 | class UEAccessCtrl(app_manager.RyuApp): 19 | OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] 20 | _CONTEXTS = {'wsgi': WSGIApplication} 21 | 22 | def __init__(self, *args, **kwargs): 23 | super(UEAccessCtrl, self).__init__(*args, **kwargs) 24 | self.mac_to_port = {} # mac address to inbound port table 25 | self.arp_broadcast = {} # arp broadcast inbound port table 26 | wsgi = kwargs['wsgi'] 27 | wsgi.register(EastWestAPI, {ue_instance_name: self}) 28 | 29 | @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER) 30 | def switch_features_handler(self, ev): 31 | datapath = ev.msg.datapath 32 | ofproto = datapath.ofproto 33 | parser = datapath.ofproto_parser 34 | 35 | # install table-miss flow entry 36 | # 37 | # We specify NO BUFFER to max_len of the output action due to 38 | # OVS bug. At this moment, if we specify a lesser number, e.g., 39 | # 128, OVS will send Packet-In with invalid buffer_id and 40 | # truncated packet data. In that case, we cannot output packets 41 | # correctly. The bug has been fixed in OVS v2.1.0. 42 | match = parser.OFPMatch() 43 | actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, 44 | ofproto.OFPCML_NO_BUFFER)] 45 | self.add_flow(datapath, 0, match, actions) 46 | 47 | def add_flow(self, datapath, priority, match, actions, buffer_id=None): 48 | ofproto = datapath.ofproto 49 | parser = datapath.ofproto_parser 50 | 51 | inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, 52 | actions)] 53 | if buffer_id: 54 | mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id, 55 | priority=priority, match=match, 56 | instructions=inst) 57 | else: 58 | mod = parser.OFPFlowMod(datapath=datapath, priority=priority, 59 | match=match, instructions=inst) 60 | datapath.send_msg(mod) 61 | 62 | @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) 63 | def _packet_in_handler(self, ev): 64 | # If you hit this you might want to increase 65 | # the "miss_send_length" of your switch 66 | if ev.msg.msg_len < ev.msg.total_len: 67 | self.logger.debug("packet truncated: only %s of %s bytes", 68 | ev.msg.msg_len, ev.msg.total_len) 69 | msg = ev.msg 70 | datapath = msg.datapath 71 | ofproto = datapath.ofproto 72 | parser = datapath.ofproto_parser 73 | in_port = msg.match['in_port'] 74 | 75 | pkt = packet.Packet(msg.data) 76 | eth = pkt.get_protocols(ethernet.ethernet)[0] 77 | dst = eth.dst 78 | src = eth.src 79 | dpid = datapath.id 80 | 81 | # ignore lldp and ipv6 packet 82 | if eth.ethertype == ether_types.ETH_TYPE_LLDP or eth.ethertype == ether_types.ETH_TYPE_IPV6: 83 | return 84 | 85 | header_list = dict((p.protocol_name, p) for p in pkt.protocols if type(p) != str) 86 | # self.logger.info(header_list) 87 | 88 | self.logger.info("Packet In: %s %s -> %s | port:%s", dpid, src, dst, in_port) 89 | 90 | if eth.ethertype == ether_types.ETH_TYPE_ARP and dst == "ff:ff:ff:ff:ff:ff": 91 | arp_dst_ip = pkt.get_protocol(arp.arp).dst_ip 92 | if (dpid, src, arp_dst_ip) in self.arp_broadcast: 93 | if self.arp_broadcast[(dpid, src, arp_dst_ip)] != in_port: 94 | out = datapath.ofproto_parser.OFPPacketOut( 95 | datapath=datapath, 96 | buffer_id=datapath.ofproto.OFP_NO_BUFFER, 97 | in_port=in_port, 98 | actions=[], data=None) 99 | datapath.send_msg(out) 100 | self.logger.info('ARP Loop Maker Dropped!') 101 | 102 | return 103 | else: # learn arp broadcast table 104 | self.arp_broadcast[(dpid, src, arp_dst_ip)] = in_port 105 | 106 | self.mac_to_port.setdefault(dpid, {}) 107 | # learn a mac address to avoid FLOOD next time. 108 | self.mac_to_port[dpid][src] = in_port 109 | 110 | if dst in self.mac_to_port[dpid]: 111 | out_port = self.mac_to_port[dpid][dst] 112 | else: 113 | out_port = ofproto.OFPP_FLOOD 114 | 115 | actions = [parser.OFPActionOutput(out_port)] 116 | 117 | # install a flow to avoid packet_in next time 118 | if out_port != ofproto.OFPP_FLOOD: 119 | match = parser.OFPMatch(in_port=in_port, eth_dst=dst, eth_src=src) 120 | # verify if we have a valid buffer_id, if yes avoid to send both 121 | # flow_mod & packet_out 122 | if msg.buffer_id != ofproto.OFP_NO_BUFFER: 123 | self.add_flow(datapath, 1, match, actions, msg.buffer_id) 124 | return 125 | else: 126 | self.add_flow(datapath, 1, match, actions) 127 | data = None 128 | if msg.buffer_id == ofproto.OFP_NO_BUFFER: 129 | data = msg.data 130 | 131 | out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id, 132 | in_port=in_port, actions=actions, data=data) 133 | datapath.send_msg(out) 134 | 135 | 136 | class EastWestAPI(ControllerBase): 137 | def __init__(self, req, link, data, **config): 138 | super(EastWestAPI, self).__init__(req, link, data, **config) 139 | self.UE_app = data[ue_instance_name] 140 | self.logger = logging.getLogger(self.__class__.__name__) 141 | self.authentication = { 142 | 'TEST': '033bd94b1168d7e4f0d644c3c95e35bf', 143 | 'URLLC': 'dfdc323ef40c8f38f5f022a5554f2dee', 144 | 'EMBB': 'e9406f9b456569f230a23d21464189f2', 145 | 'MMTC': '1d99331a7879c3c5b90998f8c3c6a9d6' 146 | } 147 | self.unauthenticated = Response( 148 | status=401, 149 | content_type='application/json', 150 | body=json.dumps( 151 | {'error': 'unauthenticated'}, 152 | indent=4 153 | ) + '\n' 154 | ) 155 | 156 | @route('helloworld', '/hello/{content}', methods=['GET']) 157 | def _echo(self, req, **kwargs): 158 | content = kwargs['content'] 159 | 160 | if content == '': 161 | return Response(body='No Content\n') 162 | else: 163 | return Response(body=(content + '\n')) 164 | 165 | @route('mac-port-table', '/mac-port-table', methods=['GET']) 166 | def _mac_port_table(self, req, **kwargs): 167 | UE_app = self.UE_app 168 | body = json.dumps(UE_app.mac_to_port, indent=4, sort_keys=True) + '\n' 169 | 170 | if 'Authentication' in req.headers: 171 | if req.headers['Authentication'] in self.authentication.values(): 172 | return Response(content_type='application/json', body=body) 173 | else: 174 | return self.unauthenticated 175 | else: 176 | return self.unauthenticated 177 | 178 | @route('post-test', '/echo-post', methods=['POST']) 179 | def _echo_post(self, req, **kwargs): 180 | rx = json.loads(req.body) 181 | body = json.dumps(rx, indent=4, sort_keys=True) + '\n' 182 | 183 | if 'Authentication' in req.headers: 184 | if req.headers['Authentication'] in self.authentication.values(): 185 | return Response(content_type='application/json', body=body) 186 | else: 187 | return self.unauthenticated 188 | else: 189 | return self.unauthenticated 190 | 191 | @route('arp-table', '/arp-table', methods=['GET']) 192 | def _arp_table(self, req, **kwargs): 193 | arp_broadcast = self.UE_app.arp_broadcast 194 | arp_str_table = {} 195 | for key in arp_broadcast.keys(): 196 | arp_str_table[str(key)] = arp_broadcast[key] 197 | body = json.dumps(arp_str_table, indent=4, sort_keys=True) + '\n' 198 | 199 | if 'Authentication' in req.headers: 200 | if req.headers['Authentication'] in self.authentication.values(): 201 | return Response(content_type='application/json', body=body) 202 | else: 203 | return self.unauthenticated 204 | else: 205 | return self.unauthenticated 206 | --------------------------------------------------------------------------------