├── .gitignore ├── LICENSE ├── README.md ├── docs └── Microflow.png ├── src ├── Makefile ├── Openflow │ ├── openflow-1.0.h │ ├── openflow-1.1.h │ ├── openflow-1.2.h │ ├── openflow-1.3.h │ ├── openflow-1.4.h │ ├── openflow-1.5.h │ ├── openflow-common.h │ ├── openflow.h │ └── types.h ├── dbg.h ├── httpserver │ ├── Makefile │ ├── Makefile~ │ ├── README.txt │ ├── cgi.c │ ├── cgi.h │ ├── main.c │ └── wrlib │ │ ├── analysis.c │ │ ├── analysis.h │ │ ├── http.c │ │ ├── http.h │ │ ├── mg_compat.c │ │ ├── mg_compat.h │ │ ├── misc.c │ │ ├── misc.h │ │ ├── request.c │ │ ├── wrhash.c │ │ ├── wrhash.h │ │ ├── wrio.c │ │ ├── wrio.h │ │ ├── wrmpool.c │ │ ├── wrmpool.h │ │ ├── wrstring.c │ │ └── wrstring.h ├── main.c ├── mf_api.h ├── mf_controller.c ├── mf_controller.h ├── mf_devicemgr.c ├── mf_devicemgr.h ├── mf_lf_list.c ├── mf_lf_list.h ├── mf_logger.c ├── mf_logger.h ├── mf_mempool.c ├── mf_mempool.h ├── mf_msg_handler.c ├── mf_msg_handler.h ├── mf_msg_parser.c ├── mf_msg_parser.h ├── mf_ofmsg_constructor.c ├── mf_ofmsg_constructor.h ├── mf_rx_queue.c ├── mf_rx_queue.h ├── mf_socket.c ├── mf_socket.h ├── mf_switch.c ├── mf_switch.h ├── mf_timer.c ├── mf_timer.h ├── mf_topomgr.c ├── mf_topomgr.h ├── mf_utilities.c ├── mf_utilities.h ├── mf_wrapper.c ├── mf_wrapper.h └── minunit.h ├── tags ├── tests ├── Makefile ├── devicemgr.c ├── host_hash_test.c ├── inverse_memcpy_test.c ├── lock_free_list_test.c ├── log_test.c ├── queue_test.c ├── socket_array_test.c ├── socket_client.c ├── socket_test.c ├── timer_test.c ├── topomgr_test.c └── wrapper_test.c └── webui ├── README.md ├── README.txt ├── icons ├── Microflow_logo.png ├── demo.png ├── host.svg ├── plvision-logo.jpg ├── router.png ├── server-fail.png └── server-ok.png ├── index.html ├── odl-rest.js ├── odl-webui.js └── styles.css /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | # Debug files 31 | *.dSYM/ 32 | tests/*.log 33 | src/*.log 34 | src/microflow 35 | callgrind.* 36 | cachegrind.* 37 | core 38 | src/perf* 39 | 40 | #VIM files 41 | *.swp 42 | *.swo 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](docs/Microflow.png) 2 | # Microflow 3 | The light-weighted, lightning fast OpenFlow SDN controller capable of multi-threads and clustering. 4 | 5 | #Build & Run 6 | cd src 7 | 8 | sudo make 9 | 10 | sudo ./microflow 11 | 12 | WebUI can be accessed at: localhost:8000 13 | 14 | #Current status 15 | 16 | 17 | ###Architecture Design DONE 18 | Async event drive 19 | Multiple lock-free recv queues 20 | One producer & Multiple workers 21 | Shared memory(trying to make it lock-free) among workers 22 | 23 | ###Socket/epoll communication DONE 24 | Enable non-blocking & Async socket interface 25 | Handled by dedicated thread & CPU core 26 | 27 | ###Multi-thread implementation DONE 28 | Separated thread for socket\worker\timer\others 29 | Allows full-utilization of CPU time when busy and zero CPU usage when free 30 | Lock-Free msg recv queue implementation 31 | CPU affinity allows to take the full advantage of multi-core CPUs 32 | 33 | ###Memory pool implementation DONE 34 | Memory pool for received msgs 35 | Eliminate time-consumption malloc/free operations 36 | Eliminate redundant memory copy actions in user space 37 | 38 | ###Timer & Logger implementation DONE 39 | Implement particular function in a cycled way 40 | Time precision is 1 ms 41 | Log particular msgs to log file with timestamp 42 | Not for real-time application 43 | 44 | ###Device manager implementation Phase I&II DONE 45 | Maintain a hash-table for all the switches & hosts in the network 46 | Pre-alloced memory cells, eliminate malloc/free 47 | 48 | ###OpenFlow msg handler implementation Phase I&II DONE 49 | Hello & Echo & Feature_request handler 50 | Packet out sender 51 | Packet_in handler 52 | Multipart reply msg handler 53 | ARP msg handler 54 | LLDP msg handler 55 | Port statistic msg handler 56 | Register/unregister customized handler according to different msg type 57 | 58 | ###Topology manager implementation Phase I DONE 59 | Maintain network links 60 | Maintain switch links 61 | Pre-alloced memory cells, eliminate malloc/free 62 | Merge lock-free list 63 | 64 | ###Logo Design DONE 65 | :D Thanks to Miss Hong :p 66 | 67 | ###Http server/Web GUI DONE 68 | Http server 69 | Web GUI based on bootstrap jQuery and D3.js 70 | 71 | ###Lock-free linked-list & hashtable 72 | Used for device manager and topo manager 73 | Eliminate performance bottleneck in multi-thread environment 74 | 75 | #TODO List 76 | 77 | ###OpenFlow msg handler implementation Phase II 78 | Statistic msgs handler 79 | Flow-mod msgs 80 | 81 | ###Topology manager implementation Phase II 82 | Path calculation 83 | 84 | ###Http server/Web GUI Phase II 85 | More WebUI features 86 | Devices(switches + hosts) status 87 | Topo status 88 | Warning/error messages 89 | Port/Link status 90 | 91 | 92 | ###Cluster 93 | A cluster service based on network games' mechanism 94 | 95 | ###Documents 96 | An introduction doc & manual 97 | Architecture design doc 98 | 99 | #Contact & Bug Report 100 | Pan Zhang 101 | dazhangpan@gmail.com 102 | -------------------------------------------------------------------------------- /docs/Microflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PanZhangg/Microflow/644a9dd80b7eb67ed61dd19c7553b14ce60f5e04/docs/Microflow.png -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = microflow 2 | MF_SOURCE = main.c ../src/mf_socket.c ../src/mf_logger.c \ 3 | ../src/mf_timer.c ../src/mf_switch.c ../src/mf_msg_handler.c ../src/mf_ofmsg_constructor.c \ 4 | ../src/mf_devicemgr.c ../src/mf_rx_queue.c ../src/mf_msg_parser.c ../src/mf_mempool.c \ 5 | ../src/mf_utilities.c ../src/mf_topomgr.c \ 6 | ../src/mf_controller.c ../src/mf_lf_list.c ../src/mf_wrapper.c\ 7 | 8 | HTTP_SOURCE = ./httpserver/wrlib/wrmpool.c ./httpserver/wrlib/wrhash.c ./httpserver/wrlib/wrstring.c ./httpserver/wrlib/misc.c ./httpserver/wrlib/wrio.c \ 9 | ./httpserver/wrlib/http.c ./httpserver/wrlib/request.c ./httpserver/wrlib/analysis.c ./httpserver/wrlib/mg_compat.c \ 10 | ./httpserver/cgi.c \ 11 | 12 | HTTP_OBJECTS = analysis.o http.o cgi.o mg_compat.o misc.o request.o wrhash.o wrio.o wrmpool.o wrstring.o 13 | 14 | LIBS = httpserver.a 15 | 16 | $(TARGET): $(MF_SOURCE) $(LIBS) 17 | cc -Wall -O3 -W -Wno-unused -Wno-sign-compare -g -D_POSIX_SOURCE -D_BSD_SOURCE -D_GNU_SOURCE -D__USE_GNU -o $@ $^ -ldl -lpthread 18 | rm $(HTTP_OBJECTS) 19 | httpserver.a : $(HTTP_OBJECTS) 20 | ar crv httpserver.a $(HTTP_OBJECTS) 21 | $(HTTP_OBJECTS) : $(HTTP_SOURCE) 22 | gcc -w -c -D_POSIX_SOURCE -D_BSD_SOURCE $^ -ldl -lpthread 23 | #analysis.o: 24 | # gcc -w -c -D_POSIX_SOURCE -D_BSD_SOURCE ./httpserver/wrlib/analysis.c -ldl -lpthread 25 | #http.o: 26 | # gcc -w -c -D_POSIX_SOURCE -D_BSD_SOURCE ./httpserver/wrlib/http.c -ldl -lpthread 27 | #cgi.o: 28 | # gcc -w -c -D_POSIX_SOURCE -D_BSD_SOURCE ./httpserver/cgi.c -ldl -lpthread 29 | #mg_compat.o: 30 | # gcc -w -c -D_POSIX_SOURCE -D_BSD_SOURCE ./httpserver/wrlib/mg_compat.c -ldl -lpthread 31 | #misc.o: 32 | # gcc -w -c -D_POSIX_SOURCE -D_BSD_SOURCE ./httpserver/wrlib/misc.c -ldl -lpthread 33 | #request.o: 34 | # gcc -w -c -D_POSIX_SOURCE -D_BSD_SOURCE ./httpserver/wrlib/request.c -ldl -lpthread 35 | #wrhash.o: 36 | # gcc -w -c -D_POSIX_SOURCE -D_BSD_SOURCE ./httpserver/wrlib/wrhash.c -ldl -lpthread 37 | #wrio.o: 38 | # gcc -w -c -D_POSIX_SOURCE -D_BSD_SOURCE ./httpserver/wrlib/wrio.c -ldl -lpthread 39 | #wrmpool.o: 40 | # gcc -w -c -D_POSIX_SOURCE -D_BSD_SOURCE ./httpserver/wrlib/wrmpool.c -ldl -lpthread 41 | #wrstring.o: 42 | # gcc -w -c -D_POSIX_SOURCE -D_BSD_SOURCE ./httpserver/wrlib/wrstring.c -ldl -lpthread 43 | clean: 44 | rm $(TARGET) $(LIBS) 45 | -------------------------------------------------------------------------------- /src/Openflow/openflow-1.2.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2008, 2011, 2012, 2013, 2014 The Board of Trustees of The Leland Stanford 2 | * Junior University 3 | * 4 | * We are making the OpenFlow specification and associated documentation 5 | * (Software) available for public use and benefit with the expectation 6 | * that others will use, modify and enhance the Software and contribute 7 | * those enhancements back to the community. However, since we would 8 | * like to make the Software available for broadest use, with as few 9 | * restrictions as possible permission is hereby granted, free of 10 | * charge, to any person obtaining a copy of this Software to deal in 11 | * the Software under the copyrights without restriction, including 12 | * without limitation the rights to use, copy, modify, merge, publish, 13 | * distribute, sublicense, and/or sell copies of the Software, and to 14 | * permit persons to whom the Software is furnished to do so, subject to 15 | * the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 24 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 25 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | * The name and trademarks of copyright holder(s) may NOT be used in 30 | * advertising or publicity pertaining to the Software or any 31 | * derivatives without specific, written prior permission. 32 | */ 33 | 34 | /* 35 | * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc. 36 | * Copyright (c) 2012 Horms Solutions Ltd. 37 | * 38 | * Licensed under the Apache License, Version 2.0 (the "License"); 39 | * you may not use this file except in compliance with the License. 40 | * You may obtain a copy of the License at: 41 | * 42 | * http://www.apache.org/licenses/LICENSE-2.0 43 | * 44 | * Unless required by applicable law or agreed to in writing, software 45 | * distributed under the License is distributed on an "AS IS" BASIS, 46 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 47 | * See the License for the specific language governing permissions and 48 | * limitations under the License. 49 | */ 50 | 51 | /* OpenFlow: protocol between controller and datapath. */ 52 | 53 | #ifndef OPENFLOW_12_H 54 | #define OPENFLOW_12_H 1 55 | 56 | #include "openflow-1.1.h" 57 | 58 | /* Error type for experimenter error messages. */ 59 | #define OFPET12_EXPERIMENTER 0xffff 60 | 61 | /* The VLAN id is 12-bits, so we can use the entire 16 bits to indicate 62 | * special conditions. 63 | */ 64 | enum ofp12_vlan_id { 65 | OFPVID12_PRESENT = 0x1000, /* Bit that indicate that a VLAN id is set */ 66 | OFPVID12_NONE = 0x0000, /* No VLAN id was set. */ 67 | }; 68 | 69 | /* Bit definitions for IPv6 Extension Header pseudo-field. */ 70 | enum ofp12_ipv6exthdr_flags { 71 | OFPIEH12_NONEXT = 1 << 0, /* "No next header" encountered. */ 72 | OFPIEH12_ESP = 1 << 1, /* Encrypted Sec Payload header present. */ 73 | OFPIEH12_AUTH = 1 << 2, /* Authentication header present. */ 74 | OFPIEH12_DEST = 1 << 3, /* 1 or 2 dest headers present. */ 75 | OFPIEH12_FRAG = 1 << 4, /* Fragment header present. */ 76 | OFPIEH12_ROUTER = 1 << 5, /* Router header present. */ 77 | OFPIEH12_HOP = 1 << 6, /* Hop-by-hop header present. */ 78 | OFPIEH12_UNREP = 1 << 7, /* Unexpected repeats encountered. */ 79 | OFPIEH12_UNSEQ = 1 << 8 /* Unexpected sequencing encountered. */ 80 | }; 81 | 82 | /* Header for OXM experimenter match fields. */ 83 | struct ofp12_oxm_experimenter_header { 84 | ovs_be32 oxm_header; /* oxm_class = OFPXMC_EXPERIMENTER */ 85 | ovs_be32 experimenter; /* Experimenter ID which takes the same 86 | form as in struct ofp11_experimenter_header. */ 87 | }; 88 | OFP_ASSERT(sizeof(struct ofp12_oxm_experimenter_header) == 8); 89 | 90 | enum ofp12_controller_max_len { 91 | OFPCML12_MAX = 0xffe5, /* maximum max_len value which can be used 92 | * to request a specific byte length. */ 93 | OFPCML12_NO_BUFFER = 0xffff /* indicates that no buffering should be 94 | * applied and the whole packet is to be 95 | * sent to the controller. */ 96 | }; 97 | 98 | /* OpenFlow 1.2 specific flags 99 | * (struct ofp12_flow_mod, member flags). */ 100 | enum ofp12_flow_mod_flags { 101 | OFPFF12_RESET_COUNTS = 1 << 2 /* Reset flow packet and byte counts. */ 102 | }; 103 | 104 | /* OpenFlow 1.2 specific capabilities 105 | * (struct ofp_switch_features, member capabilities). */ 106 | enum ofp12_capabilities { 107 | OFPC12_PORT_BLOCKED = 1 << 8 /* Switch will block looping ports. */ 108 | }; 109 | 110 | /* Full description for a queue. */ 111 | struct ofp12_packet_queue { 112 | ovs_be32 queue_id; /* id for the specific queue. */ 113 | ovs_be32 port; /* Port this queue is attached to. */ 114 | ovs_be16 len; /* Length in bytes of this queue desc. */ 115 | uint8_t pad[6]; /* 64-bit alignment. */ 116 | /* Followed by any number of queue properties expressed using 117 | * ofp_queue_prop_header, to fill out a total of 'len' bytes. */ 118 | }; 119 | OFP_ASSERT(sizeof(struct ofp12_packet_queue) == 16); 120 | 121 | /* Body of reply to OFPST_TABLE request. */ 122 | struct ofp12_table_stats { 123 | uint8_t table_id; /* Identifier of table. Lower numbered tables 124 | are consulted first. */ 125 | uint8_t pad[7]; /* Align to 64-bits. */ 126 | char name[OFP_MAX_TABLE_NAME_LEN]; 127 | ovs_be64 match; /* Bitmap of (1 << OFPXMT_*) that indicate the 128 | fields the table can match on. */ 129 | ovs_be64 wildcards; /* Bitmap of (1 << OFPXMT_*) wildcards that are 130 | supported by the table. */ 131 | ovs_be32 write_actions; /* Bitmap of OFPAT_* that are supported 132 | by the table with OFPIT_WRITE_ACTIONS. */ 133 | ovs_be32 apply_actions; /* Bitmap of OFPAT_* that are supported 134 | by the table with OFPIT_APPLY_ACTIONS. */ 135 | ovs_be64 write_setfields;/* Bitmap of (1 << OFPXMT_*) header fields that 136 | can be set with OFPIT_WRITE_ACTIONS. */ 137 | ovs_be64 apply_setfields;/* Bitmap of (1 << OFPXMT_*) header fields that 138 | can be set with OFPIT_APPLY_ACTIONS. */ 139 | ovs_be64 metadata_match; /* Bits of metadata table can match. */ 140 | ovs_be64 metadata_write; /* Bits of metadata table can write. */ 141 | ovs_be32 instructions; /* Bitmap of OFPIT_* values supported. */ 142 | ovs_be32 config; /* Bitmap of OFPTC_* values */ 143 | ovs_be32 max_entries; /* Max number of entries supported. */ 144 | ovs_be32 active_count; /* Number of active entries. */ 145 | ovs_be64 lookup_count; /* Number of packets looked up in table. */ 146 | ovs_be64 matched_count; /* Number of packets that hit table. */ 147 | }; 148 | OFP_ASSERT(sizeof(struct ofp12_table_stats) == 128); 149 | 150 | /* Number of types of groups supported by ofp12_group_features_stats. */ 151 | #define OFPGT12_N_TYPES 4 152 | 153 | /* Body of reply to OFPST12_GROUP_FEATURES request. Group features. */ 154 | struct ofp12_group_features_stats { 155 | ovs_be32 types; /* Bitmap of OFPGT11_* values supported. */ 156 | ovs_be32 capabilities; /* Bitmap of OFPGFC12_* capability supported. */ 157 | 158 | /* Each element in the following arrays corresponds to the group type with 159 | * the same number, e.g. max_groups[0] is the maximum number of OFPGT11_ALL 160 | * groups, actions[2] is the actions supported by OFPGT11_INDIRECT 161 | * groups. */ 162 | ovs_be32 max_groups[OFPGT12_N_TYPES]; /* Max number of groups. */ 163 | ovs_be32 actions[OFPGT12_N_TYPES]; /* Bitmaps of supported OFPAT_*. */ 164 | }; 165 | OFP_ASSERT(sizeof(struct ofp12_group_features_stats) == 40); 166 | 167 | /* Group configuration flags */ 168 | enum ofp12_group_capabilities { 169 | OFPGFC12_SELECT_WEIGHT = 1 << 0, /* Support weight for select groups */ 170 | OFPGFC12_SELECT_LIVENESS = 1 << 1, /* Support liveness for select groups */ 171 | OFPGFC12_CHAINING = 1 << 2, /* Support chaining groups */ 172 | OFPGFC12_CHAINING_CHECKS = 1 << 3, /* Check chaining for loops and delete */ 173 | }; 174 | 175 | /* Body for ofp12_stats_request/reply of type OFPST_EXPERIMENTER. */ 176 | struct ofp12_experimenter_stats_header { 177 | ovs_be32 experimenter; /* Experimenter ID which takes the same form 178 | as in struct ofp_experimenter_header. */ 179 | ovs_be32 exp_type; /* Experimenter defined. */ 180 | /* Experimenter-defined arbitrary additional data. */ 181 | }; 182 | OFP_ASSERT(sizeof(struct ofp12_experimenter_stats_header) == 8); 183 | 184 | /* Role request and reply message. */ 185 | struct ofp12_role_request { 186 | ovs_be32 role; /* One of OFPCR12_ROLE_*. */ 187 | uint8_t pad[4]; /* Align to 64 bits. */ 188 | ovs_be64 generation_id; /* Master Election Generation Id */ 189 | }; 190 | OFP_ASSERT(sizeof(struct ofp12_role_request) == 16); 191 | 192 | /* Controller roles. */ 193 | enum ofp12_controller_role { 194 | OFPCR12_ROLE_NOCHANGE, /* Don't change current role. */ 195 | OFPCR12_ROLE_EQUAL, /* Default role, full access. */ 196 | OFPCR12_ROLE_MASTER, /* Full access, at most one master. */ 197 | OFPCR12_ROLE_SLAVE, /* Read-only access. */ 198 | }; 199 | 200 | /* Packet received on port (datapath -> controller). */ 201 | struct ofp12_packet_in { 202 | ovs_be32 buffer_id; /* ID assigned by datapath. */ 203 | ovs_be16 total_len; /* Full length of frame. */ 204 | uint8_t reason; /* Reason packet is being sent (one of OFPR_*) */ 205 | uint8_t table_id; /* ID of the table that was looked up */ 206 | /* Followed by: 207 | * - Match 208 | * - Exactly 2 all-zero padding bytes, then 209 | * - An Ethernet frame whose length is inferred from header.length. 210 | * The padding bytes preceding the Ethernet frame ensure that the IP 211 | * header (if any) following the Ethernet header is 32-bit aligned. 212 | */ 213 | /* struct ofp12_match match; */ 214 | /* uint8_t pad[2]; Align to 64 bit + 16 bit */ 215 | /* uint8_t data[0]; Ethernet frame */ 216 | }; 217 | OFP_ASSERT(sizeof(struct ofp12_packet_in) == 8); 218 | 219 | /* Flow removed (datapath -> controller). */ 220 | struct ofp12_flow_removed { 221 | ovs_be64 cookie; /* Opaque controller-issued identifier. */ 222 | 223 | ovs_be16 priority; /* Priority level of flow entry. */ 224 | uint8_t reason; /* One of OFPRR_*. */ 225 | uint8_t table_id; /* ID of the table */ 226 | 227 | ovs_be32 duration_sec; /* Time flow was alive in seconds. */ 228 | ovs_be32 duration_nsec; /* Time flow was alive in nanoseconds beyond 229 | duration_sec. */ 230 | ovs_be16 idle_timeout; /* Idle timeout from original flow mod. */ 231 | ovs_be16 hard_timeout; /* Hard timeout from original flow mod. */ 232 | ovs_be64 packet_count; 233 | ovs_be64 byte_count; 234 | /* struct ofp12_match match; Description of fields. Variable size. */ 235 | }; 236 | OFP_ASSERT(sizeof(struct ofp12_flow_removed) == 40); 237 | 238 | #endif /* openflow/openflow-1.2.h */ 239 | -------------------------------------------------------------------------------- /src/Openflow/openflow-1.5.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2008, 2014 The Board of Trustees of The Leland Stanford 2 | * Junior University 3 | * Copyright (c) 2011, 2014 Open Networking Foundation 4 | * 5 | * We are making the OpenFlow specification and associated documentation 6 | * (Software) available for public use and benefit with the expectation 7 | * that others will use, modify and enhance the Software and contribute 8 | * those enhancements back to the community. However, since we would 9 | * like to make the Software available for broadest use, with as few 10 | * restrictions as possible permission is hereby granted, free of 11 | * charge, to any person obtaining a copy of this Software to deal in 12 | * the Software under the copyrights without restriction, including 13 | * without limitation the rights to use, copy, modify, merge, publish, 14 | * distribute, sublicense, and/or sell copies of the Software, and to 15 | * permit persons to whom the Software is furnished to do so, subject to 16 | * the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 25 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 26 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | * SOFTWARE. 29 | * 30 | * The name and trademarks of copyright holder(s) may NOT be used in 31 | * advertising or publicity pertaining to the Software or any 32 | * derivatives without specific, written prior permission. 33 | */ 34 | 35 | /* OpenFlow: protocol between controller and datapath. */ 36 | 37 | #ifndef OPENFLOW_15_H 38 | #define OPENFLOW_15_H 1 39 | 40 | #include "openflow-common.h" 41 | 42 | /* Group commands */ 43 | enum ofp15_group_mod_command { 44 | /* Present since OpenFlow 1.1 - 1.4 */ 45 | OFPGC15_ADD = 0, /* New group. */ 46 | OFPGC15_MODIFY = 1, /* Modify all matching groups. */ 47 | OFPGC15_DELETE = 2, /* Delete all matching groups. */ 48 | 49 | /* New in OpenFlow 1.5 */ 50 | OFPGC15_INSERT_BUCKET = 3,/* Insert action buckets to the already available 51 | list of action buckets in a matching group */ 52 | /* OFPGCXX_YYY = 4, */ /* Reserved for future use. */ 53 | OFPGC15_REMOVE_BUCKET = 5,/* Remove all action buckets or any specific 54 | action bucket from matching group */ 55 | }; 56 | 57 | /* Group bucket property types. */ 58 | enum ofp15_group_bucket_prop_type { 59 | OFPGBPT15_WEIGHT = 0, /* Select groups only. */ 60 | OFPGBPT15_WATCH_PORT = 1, /* Fast failover groups only. */ 61 | OFPGBPT15_WATCH_GROUP = 2, /* Fast failover groups only. */ 62 | OFPGBPT15_EXPERIMENTER = 0xFFFF, /* Experimenter defined. */ 63 | }; 64 | 65 | /* Group bucket weight property, for select groups only. */ 66 | struct ofp15_group_bucket_prop_weight { 67 | ovs_be16 type; /* OFPGBPT15_WEIGHT. */ 68 | ovs_be16 length; /* 8. */ 69 | ovs_be16 weight; /* Relative weight of bucket. */ 70 | uint8_t pad[2]; /* Pad to 64 bits. */ 71 | }; 72 | OFP_ASSERT(sizeof(struct ofp15_group_bucket_prop_weight) == 8); 73 | 74 | /* Group bucket watch port or watch group property, for fast failover groups 75 | * only. */ 76 | struct ofp15_group_bucket_prop_watch { 77 | ovs_be16 type; /* OFPGBPT15_WATCH_PORT or OFPGBPT15_WATCH_GROUP. */ 78 | ovs_be16 length; /* 8. */ 79 | ovs_be32 watch; /* The port or the group. */ 80 | }; 81 | OFP_ASSERT(sizeof(struct ofp15_group_bucket_prop_watch) == 8); 82 | 83 | /* Bucket for use in groups. */ 84 | struct ofp15_bucket { 85 | ovs_be16 len; /* Length the bucket in bytes, including 86 | this header and any padding to make it 87 | 64-bit aligned. */ 88 | ovs_be16 action_array_len; /* Length of all actions in bytes. */ 89 | ovs_be32 bucket_id; /* Bucket Id used to identify bucket*/ 90 | /* Followed by exactly len - 8 bytes of group bucket properties. */ 91 | /* Followed by: 92 | * - Exactly 'action_array_len' bytes containing an array of 93 | * struct ofp_action_*. 94 | * - Zero or more bytes of group bucket properties to fill out the 95 | * overall length in header.length. */ 96 | }; 97 | OFP_ASSERT(sizeof(struct ofp15_bucket) == 8); 98 | 99 | /* Bucket Id can be any value between 0 and OFPG_BUCKET_MAX */ 100 | enum ofp15_group_bucket { 101 | OFPG15_BUCKET_MAX = 0xffffff00, /* Last usable bucket ID */ 102 | OFPG15_BUCKET_FIRST = 0xfffffffd, /* First bucket ID in the list of action 103 | buckets of a group. This is applicable 104 | for OFPGC15_INSERT_BUCKET and 105 | OFPGC15_REMOVE_BUCKET commands */ 106 | OFPG15_BUCKET_LAST = 0xfffffffe, /* Last bucket ID in the list of action 107 | buckets of a group. This is applicable 108 | for OFPGC15_INSERT_BUCKET and 109 | OFPGC15_REMOVE_BUCKET commands */ 110 | OFPG15_BUCKET_ALL = 0xffffffff /* All action buckets in a group, 111 | This is applicable for 112 | only OFPGC15_REMOVE_BUCKET command */ 113 | }; 114 | 115 | /* Group property types. */ 116 | enum ofp_group_prop_type { 117 | OFPGPT15_EXPERIMENTER = 0xFFFF, /* Experimenter defined. */ 118 | }; 119 | 120 | /* Group setup and teardown (controller -> datapath). */ 121 | struct ofp15_group_mod { 122 | ovs_be16 command; /* One of OFPGC15_*. */ 123 | uint8_t type; /* One of OFPGT11_*. */ 124 | uint8_t pad; /* Pad to 64 bits. */ 125 | ovs_be32 group_id; /* Group identifier. */ 126 | ovs_be16 bucket_array_len; /* Length of action buckets data. */ 127 | uint8_t pad1[2]; /* Pad to 64 bits. */ 128 | ovs_be32 command_bucket_id; /* Bucket Id used as part of 129 | * OFPGC15_INSERT_BUCKET and 130 | * OFPGC15_REMOVE_BUCKET commands 131 | * execution.*/ 132 | /* Followed by: 133 | * - Exactly 'bucket_array_len' bytes containing an array of 134 | * struct ofp15_bucket. 135 | * - Zero or more bytes of group properties to fill out the overall 136 | * length in header.length. */ 137 | }; 138 | OFP_ASSERT(sizeof(struct ofp15_group_mod) == 16); 139 | 140 | /* Body of reply to OFPMP_GROUP_DESC request. */ 141 | struct ofp15_group_desc_stats { 142 | ovs_be16 length; /* Length of this entry. */ 143 | uint8_t type; /* One of OFPGT11_*. */ 144 | uint8_t pad; /* Pad to 64 bits. */ 145 | ovs_be32 group_id; /* Group identifier. */ 146 | ovs_be16 bucket_list_len; /* Length of action buckets data. */ 147 | uint8_t pad2[6]; /* Pad to 64 bits. */ 148 | /* Followed by: 149 | * - Exactly 'bucket_list_len' bytes containing an array of 150 | * struct ofp_bucket. 151 | * - Zero or more bytes of group properties to fill out the overall 152 | * length in header.length. */ 153 | }; 154 | OFP_ASSERT(sizeof(struct ofp15_group_desc_stats) == 16); 155 | 156 | #endif /* openflow/openflow-1.5.h */ 157 | -------------------------------------------------------------------------------- /src/Openflow/openflow.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at: 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef OPENFLOW_OPENFLOW_H 18 | #define OPENFLOW_OPENFLOW_H 1 19 | 20 | #include "openflow-1.0.h" 21 | #include "openflow-1.1.h" 22 | #include "openflow-1.2.h" 23 | #include "openflow-1.3.h" 24 | #include "openflow-1.4.h" 25 | #include "openflow-1.5.h" 26 | 27 | #endif /* openflow/openflow.h */ 28 | -------------------------------------------------------------------------------- /src/Openflow/types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010, 2011, 2013, 2014 Nicira, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at: 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef OPENVSWITCH_TYPES_H 18 | #define OPENVSWITCH_TYPES_H 1 19 | 20 | #include 21 | #include 22 | 23 | #ifdef __CHECKER__ 24 | #define OVS_BITWISE __attribute__((bitwise)) 25 | #define OVS_FORCE __attribute__((force)) 26 | #else 27 | #define OVS_BITWISE 28 | #define OVS_FORCE 29 | #endif 30 | 31 | /* The ovs_be types indicate that an object is in big-endian, not 32 | * native-endian, byte order. They are otherwise equivalent to uint_t. */ 33 | typedef uint16_t OVS_BITWISE ovs_be16; 34 | typedef uint32_t OVS_BITWISE ovs_be32; 35 | typedef uint64_t OVS_BITWISE ovs_be64; 36 | 37 | #define OVS_BE16_MAX ((OVS_FORCE ovs_be16) 0xffff) 38 | #define OVS_BE32_MAX ((OVS_FORCE ovs_be32) 0xffffffff) 39 | #define OVS_BE64_MAX ((OVS_FORCE ovs_be64) 0xffffffffffffffffULL) 40 | 41 | /* These types help with a few funny situations: 42 | * 43 | * - The Ethernet header is 14 bytes long, which misaligns everything after 44 | * that. One can put 2 "shim" bytes before the Ethernet header, but this 45 | * helps only if there is exactly one Ethernet header. If there are two, 46 | * as with GRE and VXLAN (and if the inner header doesn't use this 47 | * trick--GRE and VXLAN don't) then you have the choice of aligning the 48 | * inner data or the outer data. So it seems better to treat 32-bit fields 49 | * in protocol headers as aligned only on 16-bit boundaries. 50 | * 51 | * - ARP headers contain misaligned 32-bit fields. 52 | * 53 | * - Netlink and OpenFlow contain 64-bit values that are only guaranteed to 54 | * be aligned on 32-bit boundaries. 55 | * 56 | * lib/unaligned.h has helper functions for accessing these. */ 57 | 58 | /* A 32-bit value, in host byte order, that is only aligned on a 16-bit 59 | * boundary. */ 60 | typedef struct { 61 | #ifdef WORDS_BIGENDIAN 62 | uint16_t hi, lo; 63 | #else 64 | uint16_t lo, hi; 65 | #endif 66 | } ovs_16aligned_u32; 67 | 68 | /* A 32-bit value, in network byte order, that is only aligned on a 16-bit 69 | * boundary. */ 70 | typedef struct { 71 | ovs_be16 hi, lo; 72 | } ovs_16aligned_be32; 73 | 74 | /* A 64-bit value, in host byte order, that is only aligned on a 32-bit 75 | * boundary. */ 76 | typedef struct { 77 | #ifdef WORDS_BIGENDIAN 78 | uint32_t hi, lo; 79 | #else 80 | uint32_t lo, hi; 81 | #endif 82 | } ovs_32aligned_u64; 83 | 84 | typedef union { 85 | uint32_t u32[4]; 86 | struct { 87 | uint64_t lo, hi; 88 | } u64; 89 | } ovs_u128; 90 | 91 | /* A 64-bit value, in network byte order, that is only aligned on a 32-bit 92 | * boundary. */ 93 | typedef struct { 94 | ovs_be32 hi, lo; 95 | } ovs_32aligned_be64; 96 | 97 | /* ofp_port_t represents the port number of a OpenFlow switch. 98 | * odp_port_t represents the port number on the datapath. 99 | * ofp11_port_t represents the OpenFlow-1.1 port number. */ 100 | typedef uint16_t OVS_BITWISE ofp_port_t; 101 | typedef uint32_t OVS_BITWISE odp_port_t; 102 | typedef uint32_t OVS_BITWISE ofp11_port_t; 103 | 104 | /* Macro functions that cast int types to ofp/odp/ofp11 types. */ 105 | #define OFP_PORT_C(X) ((OVS_FORCE ofp_port_t) (X)) 106 | #define ODP_PORT_C(X) ((OVS_FORCE odp_port_t) (X)) 107 | #define OFP11_PORT_C(X) ((OVS_FORCE ofp11_port_t) (X)) 108 | 109 | #endif /* openvswitch/types.h */ 110 | -------------------------------------------------------------------------------- /src/dbg.h: -------------------------------------------------------------------------------- 1 | #ifndef __dbg_h__ 2 | #define __dbg_h__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef NDEBUG 9 | #define debug(M, ...) 10 | #else 11 | #define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__) 12 | #endif 13 | 14 | #define clean_errno() (errno == 0 ? "None" : strerror(errno)) 15 | 16 | #define log_err(M, ...) fprintf(stderr, "\033[31m\033[1m[ERROR]\033[0m \033[31m(%s:%d: errno: %s) " M "\n\033[0m", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) 17 | 18 | #define log_warn(M, ...) fprintf(stderr, "\033[33m\033[1m[WARN]\033[0m\033[33m(%s:%d: errno: %s) " M "\n\033[0m", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) 19 | 20 | #define log_info(M, ...) fprintf(stderr, "\033[32m\033[1m[INFO]\033[0m\033[32m " M "\n\033[0m", ##__VA_ARGS__) 21 | #define log_debug_info(M, ...) fprintf(stderr, "\033[32m\033[1m[INFO]\033[0m\033[32m(%s:%d) " M "\n\033[0m", __FILE__, __LINE__, ##__VA_ARGS__) 22 | 23 | #define check(A, M, ...) if(!(A)) { log_err(M, ##__VA_ARGS__); errno=0; goto error; } 24 | 25 | #define sentinel(M, ...) { log_err(M, ##__VA_ARGS__); errno=0; goto error; } 26 | 27 | #define check_mem(A) check((A), "Out of memory.") 28 | 29 | #define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__); errno=0; goto error; } 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/httpserver/Makefile: -------------------------------------------------------------------------------- 1 | PROG= robin 2 | SRCS= wrlib/wrmpool.c wrlib/wrhash.c wrlib/wrstring.c wrlib/misc.c wrlib/wrio.c \ 3 | wrlib/http.c wrlib/request.c wrlib/analysis.c wrlib/mg_compat.c \ 4 | main.c cgi.c 5 | COPT= -W -Os -s -D_POSIX_SOURCE -D_BSD_SOURCE 6 | WINOPT= /O2 /Oi /Os /GT /GL /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /EHsc /MD /Gy \ 7 | /W3 /nologo /Zi /D "_MBCS" /D_CRT_SECURE_NO_WARNINGS /D_CRT_SECURE_NO_DEPRECATE 8 | 9 | windows: 10 | cl $(WINOPT) $(SRCS) /link /incremental:no \ 11 | /out:$(PROG).exe ws2_32.lib advapi32.lib 12 | 13 | del *.obj *.bak *.pdb 14 | 15 | linux: 16 | gcc $(COPT) $(SRCS) -ldl -lpthread -o $(PROG) 17 | -------------------------------------------------------------------------------- /src/httpserver/Makefile~: -------------------------------------------------------------------------------- 1 | PROG= robin 2 | SRCS= wrlib/wrmpool.c wrlib/wrhash.c wrlib/wrstring.c wrlib/misc.c wrlib/wrio.c \ 3 | wrlib/http.c wrlib/request.c wrlib/analysis.c wrlib/mg_compat.c \ 4 | main.c cgi.c 5 | COPT= -W -Os -s -D_POSIX_SOURCE -D_BSD_SOURCE -DDEBUG 6 | WINOPT= /O2 /Oi /Os /GT /GL /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /EHsc /MD /Gy \ 7 | /W3 /nologo /Zi /D "_MBCS" /D_CRT_SECURE_NO_WARNINGS /D_CRT_SECURE_NO_DEPRECATE 8 | 9 | windows: 10 | cl $(WINOPT) $(SRCS) /link /incremental:no \ 11 | /out:$(PROG).exe ws2_32.lib advapi32.lib 12 | 13 | del *.obj *.bak *.pdb 14 | 15 | linux: 16 | gcc $(COPT) $(SRCS) -ldl -lpthread -o $(PROG) 17 | -------------------------------------------------------------------------------- /src/httpserver/README.txt: -------------------------------------------------------------------------------- 1 | $1 : windows 2 | you MUST have vc 2008 compiler , 3 | use vc 2008 command prompt, 4 | cd into this directory ,and type 'nmake windows' 5 | 6 | $2 : unix/linux 7 | you MUST have gcc installed ,and type 'make linux' 8 | 9 | $3: 10 | before you compile the project ,maybe you should 11 | change some value defined in http.h 12 | like : 13 | /*default listen port*/ 14 | #define PORT 8000 15 | 16 | /*default max threads*/ 17 | #define WR_MAX_THREADS 10 18 | 19 | static const char *IndexFile = "index.html" ; 20 | static const char *RootPath = "www" ; 21 | 22 | -------------------------------------------------------------------------------- /src/httpserver/cgi.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 windyrobin 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | * 22 | * $Id: cgi.c 3/14/2009 windyrobin@Gmail.com nanjing china$ 23 | */ 24 | #include "cgi.h" 25 | 26 | int cgi_page_sum(WrHttp *pHttp) 27 | { 28 | const char *lAdd ,*rAdd; 29 | int sum; 30 | char buf[32]; 31 | printf("\n--add.cgi--\n"); 32 | 33 | print_param(pHttp); 34 | lAdd = get_param_info(pHttp ,"lAdd"); 35 | rAdd = get_param_info(pHttp ,"rAdd"); 36 | sum = atoi(lAdd)+atoi(rAdd); 37 | 38 | sprintf(buf ,"%d" ,sum); 39 | wr_send_msg(pHttp ,NULL ,buf ,strlen(buf)); 40 | return 0; 41 | 42 | } 43 | 44 | int cgi_page_txt(WrHttp *pHttp) 45 | { 46 | printf("\n--txt.cgi--\n"); 47 | print_param(pHttp); 48 | wr_send_file(pHttp ,"hello.txt"); 49 | 50 | return 0; 51 | } 52 | 53 | int cgi_page_login(WrHttp *pHttp) 54 | { 55 | const char *smsg="login success"; 56 | const char *emsg="login error"; 57 | static const char *user="robin"; 58 | static const char *pwd="hood"; 59 | 60 | const char *pRet=emsg; 61 | 62 | const char *pUser ,*pPwd; 63 | printf("\n--login.cgi--\n"); 64 | print_param(pHttp); 65 | 66 | pUser = get_param_info(pHttp ,"user"); 67 | pPwd = get_param_info(pHttp ,"pwd"); 68 | if(strcmp(user ,pUser)==0 && strcmp(pwd ,pPwd)==0){ 69 | pRet = smsg; 70 | } 71 | wr_send_msg(pHttp ,NULL ,pRet ,strlen(pRet)); 72 | 73 | return 0; 74 | } 75 | 76 | void cgi_init() 77 | { 78 | /*cgi_page_add("sum.cgi" ,cgi_page_sum); 79 | cgi_page_add("txt.cgi" ,cgi_page_txt); 80 | cgi_page_add("login.cgi" ,cgi_page_login);*/ 81 | } 82 | 83 | void cgi_uninit() 84 | { 85 | 86 | } 87 | 88 | int cgi_handler(WrHttp *pHttp ,void *handle) 89 | { 90 | int ret = -1; 91 | int (*pf)(WrHttp *) = handle; 92 | 93 | return pf(pHttp); 94 | } 95 | 96 | int errorLog(WrHttp *pHttp ,const char *mess) 97 | { 98 | printf("%s\n" ,mess); 99 | return 0; 100 | } 101 | 102 | -------------------------------------------------------------------------------- /src/httpserver/cgi.h: -------------------------------------------------------------------------------- 1 | #ifndef __CGI_H__ 2 | #define __CGI_H__ 3 | 4 | #ifdef __cplusplus 5 | extern "C"{ 6 | #endif 7 | 8 | #include "wrlib/http.h" 9 | 10 | 11 | /*!!! functions that you MUST realize*/ 12 | 13 | /*add your new cgi page */ 14 | void cgi_init(); 15 | 16 | /*may be you have some memory to free*/ 17 | void cgi_uninit(); 18 | 19 | /*you can write page in c,and you can also write it in c++ 20 | so the page-handle may be a function 21 | or you can set it a point to a Class Object(c++)*/ 22 | int cgi_handler(WrHttp *pHttp ,void *handle); 23 | 24 | 25 | /*write you own log*/ 26 | int errorLog(WrHttp *pHttp ,const char *mess); 27 | 28 | 29 | /*page handler declare here*/ 30 | int cgi_page_sum(WrHttp *pHttp); 31 | int cgi_page_txt(WrHttp *pHttp); 32 | int cgi_page_login(WrHttp *pHttp); 33 | 34 | 35 | #ifdef __cplusplus 36 | } 37 | #endif 38 | 39 | #endif 40 | 41 | -------------------------------------------------------------------------------- /src/httpserver/main.c: -------------------------------------------------------------------------------- 1 | #include "cgi.h" 2 | 3 | int main(){ 4 | char buf[32]; 5 | wr_init(); 6 | while(scanf("%s" ,buf) >0){ 7 | if(strcmp("quit" ,buf) == 0) 8 | break; 9 | } 10 | 11 | wr_uninit(); 12 | } 13 | 14 | -------------------------------------------------------------------------------- /src/httpserver/wrlib/analysis.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 windyrobin 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | * 22 | * $Id: analysis.c 3/14/2009 windyrobin@Gmail.com nanjing china$ 23 | */ 24 | 25 | #include "analysis.h" 26 | #include "misc.h" 27 | 28 | /*check is supported ,in misc.h*/ 29 | int checkmethod(WrHttp *pHttp) 30 | { 31 | char *pBuf = pHttp->curPos; 32 | int ret =-1; 33 | int i; 34 | 35 | pHttp->method = pBuf; 36 | SKIP(&pBuf ,' '); 37 | 38 | pHttp->curPos = pBuf; 39 | for(i=0 ;i<3 ;++i){ 40 | if(0 == strcmp(methods[i] ,pHttp->method)){ 41 | ret = i; 42 | break; 43 | } 44 | } 45 | return ret; 46 | } 47 | 48 | int parseURL(WrHttp *pHttp) 49 | { 50 | /*we should treat url carefully to prevent security problems 51 | for we will decode url and do something according the url*/ 52 | char *ePos = NULL; 53 | char *pBuf = pHttp->curPos; 54 | TRIM_HEAD(&pBuf); 55 | pHttp->url = pBuf; 56 | SKIP(&pBuf ,' '); 57 | TRIMI_LB_TAIL(pBuf); 58 | 59 | TRIM_HEAD(&pBuf); 60 | pHttp->protocol = pBuf; 61 | SKIP(&pBuf ,'\n'); 62 | TRIMI_LB_TAIL(pBuf); 63 | 64 | pHttp->curPos = pBuf; 65 | pHttp->queryString = NULL; 66 | if(*(pHttp->method) == 'G'){ 67 | /*if empty ,index file*/ 68 | if(*(pHttp->url) == '\0'){ 69 | pHttp->url = (char *)IndexFile; 70 | }else if((ePos=strchr(pHttp->url ,'?')) != NULL){ 71 | *ePos = '\0'; 72 | pHttp->queryString = ++ePos; 73 | pHttp->paramEndPos = find_lb_end(pHttp->protocol); 74 | } 75 | } 76 | /*convert it to utf-8*/ 77 | return url_decode(pHttp->url ,pHttp->url,0); 78 | } 79 | 80 | int parseHeader(WrHttp *pHttp) 81 | { 82 | char *pBuf = pHttp->curPos; 83 | int i = -1; 84 | char *key ,*val; 85 | 86 | /*set bucket size 8 would be efficient in most cases 87 | it's easy for clean ,and hashfun is just the first letter!*/ 88 | wr_hash_init(&(pHttp->headMap) ,&(pHttp->mp) ,8); 89 | pHttp->headMap.hashfun = wr_hashfun_uchar; 90 | pHttp->headMap.hashcmp = wr_hashcasecmp_str; 91 | 92 | //while(*pBuf !='\n' && *pBuf!='\t'){ 93 | //if control character ,stop ,(\t \n \0) 94 | while(*pBuf >= 0x20 && ++iheadMap) ,key ,val); 105 | } 106 | /*if heads num exceed or SKIP run flash ,return error*/ 107 | if(++i <= MAX_HTTP_HEADERS && pBuf - pHttp->method recvLen){ 108 | /*skip the blank line ,if POST is used,we now reach postdata-head*/ 109 | SKIP(&pBuf ,'\n'); 110 | pHttp->curPos = pBuf; 111 | }else{ 112 | i = -1; 113 | } 114 | return i; 115 | } 116 | 117 | const char *get_head_info(const WrHttp *pHttp ,const char *key) 118 | { 119 | return wr_hash_find(&(pHttp->headMap) ,key); 120 | } 121 | 122 | const char *get_param_info(const WrHttp *pHttp ,const char *key) 123 | { 124 | return wr_hash_find(&(pHttp->paramMap) ,key); 125 | } 126 | 127 | void print_header(const WrHttp *pHttp) 128 | { 129 | int i; 130 | wr_hashlist *cList ; 131 | 132 | printf("\n%s %s %s\n" ,pHttp->method ,pHttp->url ,pHttp->protocol); 133 | for(i=0 ;iheadMap.size ;++i){ 134 | cList = pHttp->headMap.buckets[i]; 135 | while(cList != NULL){ 136 | printf("%s:%s\n" ,cList->key ,cList->value); 137 | cList = cList->next; 138 | } 139 | } 140 | } 141 | 142 | void print_param(const WrHttp *pHttp) 143 | { 144 | int i; 145 | wr_hashlist *cList ; 146 | for(i=0 ;iparamMap.size ;++i){ 147 | cList = pHttp->paramMap.buckets[i]; 148 | while(cList != NULL){ 149 | printf("%s:%s\n" ,cList->key ,cList->value); 150 | cList = cList->next; 151 | } 152 | } 153 | } 154 | 155 | /* 156 | check and fix the path , if path begin with '/' ,skip the seprator; 157 | if ok return 0 :static file ,1:cgi , 158 | else return 404 or 400; 159 | 160 | !!note ,the path GET/POST by utf8-encoded , 161 | so you must convert it to ANSI before you call function like 162 | stat ,read,write.... 163 | */ 164 | int checkpath(WrHttp *pHttp) 165 | { 166 | int ret = 404; 167 | char *ext = NULL; 168 | /*sql injection!!!*/ 169 | do 170 | { 171 | 172 | if(strstr(pHttp->url ,"..") != NULL){ 173 | DBG("may be sql injection.."); 174 | ret = 400; 175 | break; 176 | } 177 | DBG("utf8 : len,%d s: %s\n" ,strlen(pHttp->url) ,pHttp->url); 178 | UTF8toANSI(pHttp->url); 179 | DBG("ansi : len,%d s: %s\n" ,strlen(pHttp->url) ,pHttp->url); 180 | 181 | if(*(pHttp->url) == '/') 182 | ++(pHttp->url); 183 | if(*(pHttp->url) == '\0') 184 | pHttp->url = (char *)IndexFile; 185 | 186 | if(stat(pHttp->url ,&pHttp->st) == 0) 187 | ret = 0; 188 | else{ 189 | ext=strchr(pHttp->url ,'.'); 190 | if(ext!=NULL && strcmp(ext ,CgiExt) == 0){ 191 | /*we only use string befor .cgi to decide cgipage*/ 192 | ret = 1; 193 | } 194 | } 195 | } while(0); 196 | 197 | return ret; 198 | } 199 | 200 | /*only check cookie when cgi process, 201 | for it's non-meaning when client get static file*/ 202 | int cookieCheck(const WrHttp *pHttp) 203 | { 204 | return 0; 205 | } 206 | 207 | /*return 200 ,or 304*/ 208 | int cacheCheck(const WrHttp *pHttp) 209 | { 210 | int retCode = 200; 211 | char buf[64]; 212 | const char *oldETag = get_head_info(pHttp ,"If-None-Match"); 213 | do{ 214 | if(oldETag == NULL) 215 | break; 216 | sprintf(buf ,"%lx.%lx" ,pHttp->st.st_size ,pHttp->st.st_mtime); 217 | if(strcmp(oldETag ,buf) == 0) retCode = 304; 218 | } while(0); 219 | return retCode; 220 | } 221 | 222 | int decodeParam(WrHttp *pHttp) 223 | { 224 | static const char *skipBrake = "&=&="; 225 | char *pBuf ,*endPos; 226 | char backup[8]; 227 | char *key ,*val; 228 | int ret = 0; 229 | 230 | /*of course ,you can use postData ,they are union*/ 231 | DBG("params: \n%s\n" ,pHttp->postData); 232 | pBuf = pHttp->queryString; 233 | endPos = pHttp->paramEndPos; 234 | 235 | /*buckets 32 would be ok ,and we use the default strcmp and hashfun */ 236 | wr_hash_init(&(pHttp->paramMap) ,&(pHttp->mp) ,32); 237 | 238 | /*must place after init */ 239 | if(pBuf==NULL || *pBuf == '\0') return 0; 240 | 241 | memcpy(backup ,endPos ,4); 242 | memcpy(endPos ,skipBrake ,4); 243 | do{ 244 | key=pBuf; 245 | SKIP(&pBuf ,'='); 246 | val=pBuf; 247 | SKIP(&pBuf ,'&'); 248 | if(url_decode(key ,key ,1)<0 || url_decode(val ,val ,1)<0){ 249 | ret = -1; 250 | break; 251 | } 252 | /*the key should be null ,but val could be*/ 253 | } while(*key!='\0' && wr_hash_add(&(pHttp->paramMap) ,key ,val)>=0 && pBuf < endPos); 254 | /*if GET method ,we would override so we must restore the data ,*/ 255 | memcpy(endPos ,backup ,4); 256 | 257 | return (ret ==0 && pBuf== ++endPos) ? 1 : -1 ; 258 | } 259 | 260 | -------------------------------------------------------------------------------- /src/httpserver/wrlib/analysis.h: -------------------------------------------------------------------------------- 1 | #include "http.h" 2 | 3 | #ifndef __ANALYSIS_H__ 4 | #define __ANALYSIS_H__ 5 | 6 | #ifdef __cplusplus 7 | extern "C"{ 8 | #endif 9 | 10 | int checkmethod(WrHttp *pHttp); 11 | int parseURL(WrHttp *pHttp); 12 | int parseHeader(WrHttp *pHttp); 13 | int checkpath(WrHttp *pHttp); 14 | int cookieCheck(const WrHttp *pHttp); 15 | int cacheCheck(const WrHttp *pHttp); 16 | int decodeParam(WrHttp *pHttp); 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | #endif 22 | 23 | -------------------------------------------------------------------------------- /src/httpserver/wrlib/http.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 windyrobin 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | * 22 | * $Id: http.c 3/14/2009 windyrobin@Gmail.com nanjing china$ 23 | */ 24 | #include "../cgi.h" 25 | #include "misc.h" 26 | #include "http.h" 27 | #include "wrhash.h" 28 | 29 | /* 30 | void wr_lock() 31 | { 32 | #ifdef _WIN32 33 | EnterCriticalSection(&WrContext.lock); 34 | #else 35 | pthread_mutex_lock(&WrContext.lock); 36 | #endif 37 | } 38 | 39 | void wr_unlock() 40 | { 41 | #ifdef _WIN32 42 | LeaveCriticalSection(&WrContext.lock); 43 | #else 44 | pthread_mutex_unlock(&WrContext.lock); 45 | #endif 46 | } 47 | */ 48 | 49 | void wr_sleep(size_t ms) 50 | { 51 | #ifdef _WIN32 52 | Sleep(ms); 53 | #else 54 | usleep(ms*1000); 55 | #endif 56 | } 57 | 58 | int wr_uninit() 59 | { 60 | WrContext.quitFlag = 1; 61 | while(WrContext.threadCnt >0) wr_sleep(WR_SOCK_RTT); 62 | /*may be you have some memory to be freed*/ 63 | cgi_uninit(); 64 | 65 | /* 66 | #ifdef _WIN32 67 | DeleteCriticalSection(&WrContext.lock); 68 | #else 69 | pthread_mutex_destroy(&WrContext.lock); 70 | #endif 71 | */ 72 | wr_hash_clear(&WrContext.mimeMap); 73 | wr_hash_clear(&WrContext.pageMap); 74 | printf("...robin quit...\n"); 75 | return 0; 76 | } 77 | 78 | 79 | /*defined in request.c*/ 80 | void requestHandler(void * s); 81 | 82 | static int wr_http_start() 83 | { 84 | SOCKET ser_fd, cli_fd; /* listen on sock_fd, new connection on new_fd */ 85 | struct sockaddr_in ser_addr ,cli_addr; /* connector's address information */ 86 | int opt ,sin_size; 87 | /* 88 | * Setup the default values 89 | */ 90 | #ifdef _WIN32 91 | int tv = WR_SOCK_RTT; 92 | WSADATA ws; 93 | WSAStartup(0x202,&ws); 94 | #else 95 | struct timeval tv; 96 | tv.tv_sec = 0; 97 | tv.tv_usec = WR_SOCK_RTT*1000; 98 | #endif 99 | /* 100 | * Setup the sockets and wait and process connections 101 | */ 102 | 103 | if ((ser_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { 104 | perror("socket"); 105 | exit(1); 106 | } 107 | 108 | /* Let the kernel reuse the socket address. This lets us run 109 | twice in a row, without waiting for the (ip, port) tuple 110 | to time out. */ 111 | opt = 1; 112 | setsockopt(ser_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)); 113 | setsockopt(ser_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)); 114 | 115 | ser_addr.sin_family = AF_INET; /* host byte order */ 116 | ser_addr.sin_port = htons(PORT); /* short, network byte order */ 117 | ser_addr.sin_addr.s_addr = INADDR_ANY; /* auto-fill with my IP */ 118 | 119 | if (bind(ser_fd, (struct sockaddr *)&ser_addr, sizeof(struct sockaddr)) == -1){ 120 | perror("bind"); 121 | exit(1); 122 | } 123 | 124 | if (listen(ser_fd, WR_SOCK_BACKLOG) == -1) { 125 | perror("listen"); 126 | exit(1); 127 | } 128 | 129 | chdir(RootPath); 130 | DBG("\nwrHttp is running...\n"); 131 | sin_size = sizeof(struct sockaddr_in); 132 | while(1){ /* main accept() loop */ 133 | if(WrContext.quitFlag == 1) 134 | break; 135 | if ((cli_fd = accept(ser_fd, (struct sockaddr *)&cli_addr, &sin_size)) == -1) 136 | continue; 137 | while(1){ 138 | if(WrContext.threadCnt < WR_MAX_THREADS){ 139 | start_thread(requestHandler ,cli_fd); 140 | break; 141 | } 142 | else 143 | wr_sleep(50); 144 | } 145 | } 146 | return 0; 147 | } 148 | 149 | const char *get_mime_type(const char *path) 150 | { 151 | const char *extension; 152 | const char *ret=NULL; 153 | if (path!=NULL && (extension = strrchr(path, '.')) != NULL) { 154 | ret = wr_hash_find(&WrContext.mimeMap ,++extension); 155 | } 156 | return (ret!=NULL) ? ret : ("text/plain"); 157 | } 158 | 159 | void cgi_page_add(const char * pageName,\ 160 | void *f) 161 | { 162 | wr_hash_add(&WrContext.pageMap ,pageName ,f); 163 | } 164 | 165 | void* cgi_page_find(const char *pageName) 166 | { 167 | return wr_hash_find(&WrContext.pageMap ,pageName); 168 | } 169 | 170 | int wr_init() 171 | { 172 | int i=-1; 173 | /*(97+97) * 4 = 800 ,assume page number is 50 and mimitype is 50 , 174 | so 100*sizeof(hash_list) = 1200 ,so 2048 is just ok*/ 175 | static char pool[2048]; 176 | static wr_mpool mpool; 177 | 178 | wr_mpool_init(&mpool ,pool ,sizeof(pool)); 179 | wr_hash_init(&WrContext.mimeMap ,&mpool ,97); 180 | wr_hash_init(&WrContext.pageMap ,&mpool ,97); 181 | WrContext.pageMap.hashcmp = wr_hashcasecmp_str; 182 | WrContext.mimeMap.hashcmp = wr_hashcasecmp_str; 183 | /*add mime type map*/ 184 | while(mmt[++i].ext != NULL){ 185 | wr_hash_add(&WrContext.mimeMap ,mmt[i].ext ,mmt[i].type); 186 | } 187 | 188 | WrContext.quitFlag = 0; 189 | WrContext.threadCnt = 0; 190 | 191 | /* 192 | #ifdef _WIN32 193 | InitializeCriticalSection(&WrContext.lock); 194 | #else 195 | pthread_mutet_init(&WrContext.lock ,NULL); 196 | #endif 197 | */ 198 | /*you must realize this fun in cgi.c*/ 199 | cgi_init(); 200 | return start_thread(wr_http_start ,NULL); 201 | } 202 | 203 | -------------------------------------------------------------------------------- /src/httpserver/wrlib/http.h: -------------------------------------------------------------------------------- 1 | #ifndef __HTTP_H__ 2 | #define __HTTP_H__ 3 | 4 | #ifdef __cplusplus 5 | extern "C"{ 6 | #endif 7 | 8 | #include "mg_compat.h" 9 | #include "wrhash.h" 10 | 11 | static const char *IndexFile = "index.html" ; 12 | static const char *RootPath = "../webui" ; 13 | static const char *CgiExt = ".cgi" ; 14 | 15 | /*for cache use ,default is ony-day ,if not expire ,we 16 | just result http-304 ,not modified*/ 17 | static long ExpireTime = 24*60*60 ; 18 | 19 | 20 | #define SERVER "Robin\/1.1" 21 | /*default listen port*/ 22 | #define PORT 8000 23 | 24 | /*the max threads ,if you use it as embedded ,maybe 10 is enough*/ 25 | #define WR_MAX_THREADS 10 26 | /*socket receive timeout ,500ms may be ok*/ 27 | #define WR_SOCK_RTT 500 28 | /*max pending-socket number*/ 29 | #define WR_SOCK_BACKLOG 5 30 | 31 | /*max heads ,http/1.1 support max:64 ,but 32 | here we only support 40*/ 33 | #define MAX_HTTP_HEADERS 40 34 | 35 | /*we use it when read/write file*/ 36 | #define PAGE_SIZE 4096 37 | 38 | /*when use GET-method ,the sum of header and url 39 | shouldn't exceed this numberwhen use POST 40 | the header should also could exceed this number 41 | otherwise return http_code-400*/ 42 | #define MAX_HEADER_SIZE 2*1024 43 | 44 | /*when use POST-method and use www-form-url-encoded 45 | the content-length shouldn't exceed this number, 46 | of course you can change this value ,but i suggest that 47 | the value is not >= 64*1024 48 | if you upload file ,this limit-size unwork ,and you sholud 49 | write the corresponding module by yourself,and i strongly 50 | recommend you write the code carefully to handle segment-data 51 | problem*/ 52 | #define MAX_POST_SIZE 8*1024 53 | 54 | /* the max size we read socket once*/ 55 | #define WR_TCP_QUAN 2*1024 56 | 57 | typedef struct{ 58 | char * method; 59 | char *url; 60 | char *protocol; 61 | 62 | union{ 63 | char *queryString; /*for get*/ 64 | char *postData; /*for post*/ 65 | }; 66 | wr_mpool mp; 67 | wr_hashmap headMap; 68 | wr_hashmap paramMap; 69 | 70 | /*the file stat(if static file)*/ 71 | struct stat st; 72 | SOCKET sock; 73 | int recvLen; 74 | char *curPos; 75 | char *paramEndPos; 76 | }WrHttp; 77 | 78 | static struct{ 79 | wr_hashmap mimeMap; 80 | wr_hashmap pageMap; 81 | volatile int threadCnt; 82 | volatile int quitFlag; 83 | /* 84 | #ifdef _WIN32 85 | CRITIACL_SECTIONI lock; 86 | #else 87 | pthread_mutext_t lock; 88 | #endif 89 | */ 90 | }WrContext; 91 | 92 | 93 | /*!!! functions export!!*/ 94 | 95 | /*defined in http.c*/ 96 | int wr_init(); 97 | int wr_uninit(); 98 | void cgi_page_add(const char * pageName ,void *); 99 | void* cgi_page_find(const char *pageName); 100 | 101 | 102 | /*defined in misc.c*/ 103 | int UTF8toANSI(char *src); 104 | 105 | 106 | /*defined in analysis.c*/ 107 | void print_header(const WrHttp *pHttp); 108 | void print_param(const WrHttp *pHttp); 109 | const char *get_head_info(const WrHttp *pHttp ,const char *key); 110 | const char *get_param_info(const WrHttp *pHttp ,const char *key); 111 | 112 | 113 | /*defined in request.c*/ 114 | const char *get_mime_type(const char *path); 115 | int wr_send_msg(WrHttp *pHttp ,const char *type ,const char *buf ,size_t len); 116 | /*send file to pHttp->sock ,will change pHttp->filePath & st*/ 117 | int wr_send_file(WrHttp *pHttp ,const char *filePath); 118 | int wr_error_reply(const WrHttp *pHttp ,int stscode); 119 | 120 | #ifdef __cplusplus 121 | } 122 | #endif 123 | 124 | #endif 125 | 126 | -------------------------------------------------------------------------------- /src/httpserver/wrlib/mg_compat.c: -------------------------------------------------------------------------------- 1 | /*this file is copied from mongoose.c*/ 2 | 3 | /* 4 | * Copyright (c) 2004-2009 Sergey Lyubka 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | * $Id: mongoose.c 200 2009-01-04 15:13:14Z valenok $ 25 | */ 26 | #include "mg_compat.h" 27 | #include "misc.h" 28 | 29 | #ifdef _WIN32 30 | static void 31 | fix_directory_separators(char *path) 32 | { 33 | for (; *path != '\0'; path++) { 34 | if (*path == '/') 35 | *path = '\\'; 36 | if (*path == '\\') 37 | while (path[1] == '\\' || path[1] == '/') 38 | (void) memmove(path + 1, 39 | path + 2, strlen(path + 2) + 1); 40 | } 41 | } 42 | 43 | int 44 | start_thread(void * (*func)(void *), void *param) 45 | { 46 | return (_beginthread((void (__cdecl *)( void *))func, 0, param) == 0); 47 | } 48 | 49 | #else 50 | 51 | void 52 | set_close_on_exec(int fd) 53 | { 54 | (void) fcntl(fd, F_SETFD, FD_CLOEXEC); 55 | } 56 | 57 | int 58 | start_thread(void * (*func)(void *), void *param) 59 | { 60 | pthread_t thread_id; 61 | pthread_attr_t attr; 62 | int retval; 63 | 64 | (void) pthread_attr_init(&attr); 65 | (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 66 | 67 | if ((retval = pthread_create(&thread_id, &attr, func, param)) != 0) 68 | DBG("%s: %s", __func__, strerror(retval)); 69 | 70 | return (retval); 71 | } 72 | 73 | #endif /* _WIN32 */ 74 | -------------------------------------------------------------------------------- /src/httpserver/wrlib/mg_compat.h: -------------------------------------------------------------------------------- 1 | #ifndef __MG_COMPAT_H__ 2 | #define __MG_COMPAT_H__ 3 | 4 | #ifdef __cplusplus 5 | extern "C"{ 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #ifdef _WIN32 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | /* 24 | #if !defined(_POSIX_) 25 | #define _POSIX_ 26 | #endif 27 | */ 28 | 29 | typedef HANDLE pthread_mutex_t; 30 | typedef HANDLE pthread_cond_t; 31 | 32 | #define WR_SOCK_ERRNO WSAGetLastError() 33 | #define WR_EINTR WSAEINTR 34 | #define EWOULDBLOCK WSAEWOULDBLOCK 35 | 36 | #if !defined(S_ISDIR) 37 | #define S_ISDIR(x) ((x) & _S_IFDIR) 38 | #endif /* S_ISDIR */ 39 | 40 | /*would conflict with iostream*/ 41 | #ifndef __cplusplus 42 | #define write(x, y, z) _write(x, y, (unsigned) z) 43 | #define read(x, y, z) _read(x, y, (unsigned) z) 44 | #define open(x, y) _open(x, y) 45 | #define lseek(x, y, z) _lseek(x, y, z) 46 | #define close(x) _close(x) 47 | #endif 48 | 49 | #define chdir(x) _chdir(x) 50 | 51 | #else /* UNIX specific */ 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #define DIRSEP '/' 67 | #define IS_DIRSEP_CHAR(c) ((c) == '/') 68 | #define O_BINARY 0 69 | #define closesocket(a) close(a) 70 | #define ERRNO errno 71 | #define INVALID_SOCKET (-1) 72 | typedef int SOCKET; 73 | 74 | #define WR_SOCK_ERRNO errno 75 | #define WR_EINTR EINTR 76 | #endif /* End of Windows and UNIX specific includes */ 77 | 78 | 79 | #if !defined(MIN) 80 | #define MIN(a ,b) ((a)<(b)?(a):(b)) 81 | #endif 82 | 83 | #if !defined(MAX) 84 | #define MAX(a ,b) ((a)>(b)?(a):(b)) 85 | #endif 86 | 87 | /*defined in mg_compat.c*/ 88 | int start_thread(void * (*func)(void *), void *param); 89 | 90 | #ifdef __cplusplus 91 | } 92 | #endif 93 | 94 | #endif 95 | 96 | -------------------------------------------------------------------------------- /src/httpserver/wrlib/misc.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PanZhangg/Microflow/644a9dd80b7eb67ed61dd19c7553b14ce60f5e04/src/httpserver/wrlib/misc.c -------------------------------------------------------------------------------- /src/httpserver/wrlib/misc.h: -------------------------------------------------------------------------------- 1 | #ifndef _MISC_H__ 2 | #define _MISC_H__ 3 | 4 | #ifdef __cplusplus 5 | extern "C"{ 6 | #endif 7 | 8 | #include "http.h" 9 | #include "wrstring.h" 10 | 11 | void DBG(const char *fmt, ...); 12 | int url_decode(const char *src ,char *dst ,int is_form_url_encoded); 13 | int UTF8toANSI(char *src); 14 | 15 | 16 | static const char *methods[3]={"HEAD" ,"GET" ,"POST"}; 17 | 18 | 19 | /*copy form moogoose*/ 20 | static const struct { 21 | const char *ext; 22 | const char *type; 23 | } mmt[] = { 24 | {"html", "text/html" }, 25 | {"htm", "text/html" }, 26 | {"shtm", "text/html" }, 27 | {"shtml", "text/html" }, 28 | {"css", "text/css" }, 29 | {"js", "application/x-javascript" }, 30 | {"ico", "image/x-icon" }, 31 | {"gif", "image/gif" }, 32 | {"jpg", "image/jpeg" }, 33 | {"jpeg", "image/jpeg" }, 34 | {"png", "image/png" }, 35 | {"svg", "image/svg+xml" }, 36 | {"torrent", "application/x-bittorrent" }, 37 | {"wav", "audio/x-wav" }, 38 | {"mp3", "audio/x-mp3" }, 39 | {"mid", "audio/mid" }, 40 | {"m3u", "audio/x-mpegurl" }, 41 | {"ram", "audio/x-pn-realaudio" }, 42 | {"ra", "audio/x-pn-realaudio" }, 43 | {"doc", "application/msword", }, 44 | {"exe", "application/octet-stream" }, 45 | {"zip", "application/x-zip-compressed" }, 46 | {"xls", "application/excel" }, 47 | {"tgz", "application/x-tar-gz" }, 48 | {"tar.gz", "application/x-tar-gz" }, 49 | {"tar", "application/x-tar" }, 50 | {"gz", "application/x-gunzip" }, 51 | {"arj", "application/x-arj-compressed" }, 52 | {"rar", "application/x-arj-compressed" }, 53 | {"rtf", "application/rtf" }, 54 | {"pdf", "application/pdf" }, 55 | {"swf", "application/x-shockwave-flash" }, 56 | {"mpg", "video/mpeg" }, 57 | {"mpeg", "video/mpeg" }, 58 | {"asf", "video/x-ms-asf" }, 59 | {"avi", "video/x-msvideo" }, 60 | {"bmp", "image/bmp" }, 61 | {NULL, NULL} 62 | }; 63 | 64 | #ifdef __cplusplus 65 | } 66 | #endif 67 | #endif 68 | 69 | -------------------------------------------------------------------------------- /src/httpserver/wrlib/request.c: -------------------------------------------------------------------------------- 1 | 2 | #include "wrstring.h" 3 | #include "misc.h" 4 | #include "analysis.h" 5 | #include "wrio.h" 6 | #include "../cgi.h" 7 | 8 | /*set mimetype ,content length ,and cache control 9 | like expire and last-modified 10 | */ 11 | static int fileSet(char *buf ,const WrHttp *pHttp) 12 | { 13 | // strftime(timeStr ,sizeof(timeStr) ,st.st_mtime) 14 | //printf("%llu\n" ,st.st_size); 15 | return sprintf(buf ,"Content-Type: %s\n" 16 | "Content-Length: %d\n" 17 | "Cache-Control: max-age=%ld\n" 18 | "ETag: %lx.%lx\n", 19 | get_mime_type(pHttp->url), 20 | pHttp->st.st_size, 21 | ExpireTime, 22 | pHttp->st.st_size, 23 | pHttp->st.st_mtime 24 | ); 25 | } 26 | 27 | static int typeSet(char *buf ,const char *type) 28 | { 29 | return sprintf(buf ,"Content-Type: %s\n" ,get_mime_type(type)); 30 | } 31 | 32 | static int lengthSet(char *buf ,int len) 33 | { 34 | return sprintf(buf ,"Content-Length: %d\n" ,len); 35 | } 36 | 37 | /*session and cookie detect ,if you need it 38 | please redifine it*/ 39 | static int cookieSet(char *buf) 40 | { 41 | return 0; 42 | } 43 | 44 | /*if keep alive was used ! 45 | should check httpinfo like "Connection:close" 46 | but here ,i just set it always live when send file!! 47 | if flat is '1' ,will always set 'close',this mean some error has occurred 48 | httpInfo was ingnored 49 | */ 50 | static int liveSet(char *buf ,const WrHttp *pHttp ,int closeflag) 51 | { 52 | return sprintf(buf ,"Connection: %s\n" ,(closeflag==1) ? "close" :"Keep-Alive") ; 53 | //return sprintf(buf ,"Connection: close\n\n") ; 54 | } 55 | 56 | /* just add '\n' to head info ,only here we use 'send' method 57 | in order to be portable in future*/ 58 | static int sendHead(const WrHttp *pHttp ,char *pBuf ,size_t len) 59 | { 60 | size_t nLen; 61 | nLen = sprintf(pBuf+len ,"Server :"SERVER"\n\n"); 62 | DBG("%s" ,pBuf); 63 | return wr_sock_nwrite(pHttp->sock ,pBuf ,len+nLen); 64 | } 65 | 66 | static int codeSet(char *pBuf ,int code) 67 | { 68 | static const char *c200 = "OK"; 69 | static const char *c304 = "Not Modified"; 70 | static const char *c400 = "Bad Request"; 71 | static const char *c404 = "Not Found"; 72 | static const char *c501 = "Not Implemented" ; 73 | 74 | const char *msg =NULL; 75 | switch(code){ 76 | case 200: 77 | msg= c200; 78 | break; 79 | case 304: 80 | msg = c304; 81 | break; 82 | case 400: 83 | msg = c400; 84 | break; 85 | case 404: 86 | msg = c404; 87 | break; 88 | case 501: 89 | msg = c501; 90 | break; 91 | default: 92 | break; 93 | } 94 | return sprintf(pBuf ,"HTTP/1.1 %d %s\n" ,code ,msg); 95 | } 96 | 97 | /* 98 | now only support: 99 | 400 Bad Request 100 | 404 not Found 101 | 405 Method not Allow 102 | if error occured ,the IE/FF will close the socket, 103 | so we should alse break the seeion thread 104 | 105 | NOTE: 304 Not Modified and 200 OK shouldn't be passed here 106 | they are default keep-alive!! 107 | */ 108 | int wr_error_reply(const WrHttp *pHttp ,int stscode) 109 | { 110 | /*only error code and server info are send ,128 would be ok! 111 | and server string shouldn't too long*/ 112 | char buf[128]; 113 | char *pBuf = buf; 114 | int closeflag = 1; 115 | 116 | pBuf += codeSet(pBuf ,stscode); 117 | //pBuf += liveSet(pBuf ,pHttp ,1); 118 | /*if method is head or get ,this mean only head info ,body not exsited, 119 | we could reuse the thread*/ 120 | /*if(*(pHttp->method) <= 'H') 121 | if(pHttp->curPos - pHttp->method < WR_BUF_SIZE) 122 | closeflag = 0; 123 | pBuf += liveSet(pBuf ,pHttp ,closeflag); 124 | printf("%s\n" ,pHttp->filePath); 125 | ret =sendHead(sock ,buf ,pBuf); 126 | if(ret >= 0 && 0==closeflag) ret = 0; 127 | else ret = -1; 128 | */ 129 | return sendHead(pHttp ,buf ,pBuf-buf); 130 | } 131 | 132 | int wr_send_msg(WrHttp *pHttp ,const char *type ,const char *buf ,size_t len) 133 | { 134 | char hBuf[BUFSIZ]; 135 | char *pBuf = hBuf; 136 | int ret; 137 | pBuf += codeSet(pBuf ,200); 138 | pBuf += typeSet(pBuf ,type); 139 | pBuf += lengthSet(pBuf ,len); 140 | 141 | do{ 142 | if((ret=sendHead(pHttp ,hBuf ,pBuf-hBuf)) <0) 143 | break; 144 | if(ret=wr_sock_nwrite(pHttp->sock ,buf ,len) <0) 145 | break; 146 | } while(0); 147 | return ret; 148 | } 149 | 150 | /*this function should only be called by cgi process 151 | so pHttp->stat and pHttp->filePath is not used 152 | here we reuse the struct 153 | if ok return 0 or last send size 154 | else reutrn < 0 155 | */ 156 | int wr_send_file(WrHttp *pHttp ,const char *filePath) 157 | { 158 | char buf[BUFSIZ]; 159 | char *pBuf = buf; 160 | int ret = 0; 161 | pBuf += codeSet(pBuf ,200); 162 | pHttp->url = (char *)filePath; 163 | stat(filePath ,&pHttp->st); 164 | pBuf += fileSet(pBuf ,pHttp); 165 | do 166 | { 167 | if((ret =sendHead(pHttp ,buf ,pBuf-buf)) <0) 168 | break; 169 | if((ret =sendFileStream(pHttp ,filePath)) <0) 170 | break; 171 | } while(0); 172 | return ret; 173 | } 174 | 175 | static int staticProcess(const WrHttp *pHttp) 176 | { 177 | char buf[BUFSIZ]; 178 | char *pBuf = buf; 179 | int ret =0; 180 | 181 | int code = cacheCheck(pHttp); 182 | pBuf += codeSet(pBuf ,code); 183 | /*default is keep-alive*/ 184 | //pBuf += liveSet(pBuf ,pHttp ,0); 185 | if(code == 200){ 186 | pBuf += fileSet(pBuf ,pHttp); 187 | } 188 | do{ 189 | /*if send error return -1*/ 190 | if((ret=sendHead(pHttp,buf ,pBuf-buf)) < 0) 191 | break; 192 | /*if 304 or method == HEAD return 0k*/ 193 | if(code==304 || 'H'==*(pHttp->method)) 194 | break; 195 | ret = sendFileStream(pHttp ,pHttp->url); 196 | } while(0); 197 | return ret; 198 | } 199 | 200 | /*if ok return 0 201 | else return retcode*/ 202 | static int cgiProcess(WrHttp *pHttp) 203 | { 204 | int ret = 0; 205 | void *handle = NULL ; 206 | do{ 207 | if((handle=cgi_page_find(pHttp->url)) == NULL){ 208 | errorLog(pHttp ,"cgi page not find"); 209 | ret = -1; 210 | break; 211 | } 212 | /*when is POST method ,maybe we should read socket*/ 213 | if(('P'==*(pHttp->method)) && wr_load_body(pHttp) < 0){ 214 | errorLog(pHttp ,"body check error"); 215 | ret = -2; 216 | break; 217 | } 218 | if(decodeParam(pHttp) < 0){ 219 | errorLog(pHttp ,"param decode error"); 220 | ret = -3; 221 | break; 222 | } 223 | if(cgi_handler(pHttp ,handle) < 0){ 224 | errorLog(pHttp ,"handler error"); 225 | ret = -4; 226 | } 227 | }while(0); 228 | 229 | /*when postData is two long ,we malloc postData , 230 | so we must free it*/ 231 | if(*(pHttp->method)=='P' && pHttp->postData!=pHttp->curPos) free(pHttp->postData); 232 | 233 | wr_hash_clear(&(pHttp->paramMap)); 234 | return ret; 235 | } 236 | 237 | static void clearHttp(WrHttp *pHttp) 238 | { 239 | wr_hash_clear(&(pHttp->headMap)); 240 | wr_mpool_clear(&(pHttp->mp)); 241 | } 242 | 243 | /*if some error occured ,break the session 244 | if code <400 ,return 0*/ 245 | static int replyHandler(WrHttp *pHttp) 246 | { 247 | int rType; 248 | int ret = -1; 249 | 250 | rType = checkpath(pHttp); 251 | DBG("filetype : %d\n" ,rType); 252 | switch (rType){ 253 | case 0://static file 254 | ret = staticProcess(pHttp); 255 | break; 256 | case 1://dyanamic page,'.cgi' extension 257 | ret = cgiProcess(pHttp); 258 | break; 259 | default: 260 | wr_error_reply(pHttp ,rType); 261 | } 262 | clearHttp(pHttp); 263 | /*if error occured ,return -1 ,we should break the session*/ 264 | return ret; 265 | } 266 | 267 | 268 | void requestHandler(void * s) 269 | { 270 | SOCKET sock= (SOCKET)s; 271 | char recvBuf[MAX_HEADER_SIZE + 8]; 272 | 273 | /*head buckets is 8 ,param buckets is 32 ,(8+32)*4 = 160 274 | left 352 ,352/sizeof(hash_list) = 352/12 = 30,i think that's enough*/ 275 | char pool[512]; 276 | int ret = -1; 277 | static const char *skipBrake = " \n\n:\n\n"; 278 | WrHttp httpInfo; 279 | 280 | ++WrContext.threadCnt; 281 | 282 | httpInfo.sock = sock; 283 | wr_mpool_init(&httpInfo.mp ,pool ,sizeof(pool)); 284 | /*we break the connetion(or thread ,session) to clear socket 285 | when any error occurred! 286 | */ 287 | do{ 288 | if(WrContext.quitFlag == 1) 289 | break; 290 | httpInfo.recvLen =wr_read_head(sock ,recvBuf ,MAX_HEADER_SIZE); 291 | if(httpInfo.recvLen <= 0) 292 | break; 293 | 294 | httpInfo.curPos = recvBuf ; 295 | recvBuf[httpInfo.recvLen] = '\0'; 296 | /*very import!! to avoid SKIP macro to run flash!!*/ 297 | strcat(recvBuf+httpInfo.recvLen ,skipBrake); 298 | 299 | /*if method not Implemented*/ 300 | if(checkmethod(&httpInfo) < 0){ 301 | DBG("len :%d %s\n" ,httpInfo.method); 302 | wr_error_reply(&httpInfo ,501); 303 | break; 304 | } 305 | if(parseURL(&httpInfo) <0){ 306 | wr_error_reply(&httpInfo ,400); 307 | errorLog(&httpInfo ,"parseURL error"); 308 | break; 309 | } 310 | /*if parse head error*/ 311 | if(parseHeader(&httpInfo) < 0){ 312 | wr_error_reply(&httpInfo ,400);//bad Request,should break;to clean data; 313 | errorLog(&httpInfo ,"parse head error"); 314 | clearHttp(&httpInfo); 315 | break; 316 | } 317 | //print_header(&httpInfo); 318 | /*if reply error */ 319 | if(replyHandler(&httpInfo) < 0){ 320 | //errorReply(&httpInfo ,400);//bad Request,should break;to clean data; 321 | //errorLog(&httpInfo ,"reply error"); 322 | break; 323 | } 324 | }while(1); 325 | 326 | closesocket(sock); 327 | --WrContext.threadCnt; 328 | 329 | DBG("---threads : %d----\n" ,WrContext.threadCnt); 330 | } 331 | -------------------------------------------------------------------------------- /src/httpserver/wrlib/wrhash.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 windyrobin 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | * 22 | * $Id: wrhash.c 3/14/2009 windyrobin@Gmail.com nanjing china$ 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "wrhash.h" 30 | 31 | void wr_hash_init(wr_hashmap* hm ,wr_mpool *mp ,size_t _size) 32 | { 33 | assert(mp != NULL); 34 | hm->mpool = mp; 35 | hm->buckets = (wr_hashlist **)wr_mpool_malloc(mp ,sizeof(int) * _size); 36 | //hm->buckets = (wr_hashlist **)malloc(sizeof(int) * _size); 37 | memset(hm->buckets ,0 ,sizeof(int) * _size); 38 | hm->size = _size; 39 | 40 | /*in default we use string fun 41 | so you must init hash before you set hashcmp 42 | and hashfun ,otherwise it would be overwrite*/ 43 | hm->hashcmp = wr_hashcmp_str; 44 | hm->hashfun = wr_hashfun_str; 45 | } 46 | 47 | void wr_hash_clear(wr_hashmap *hm) 48 | { 49 | wr_hashlist *nl,*cl; 50 | int i; 51 | 52 | do{ 53 | /*needn't to clear*/ 54 | if(hm->mpool->cflag == 0) 55 | break; 56 | for(i=0 ;isize ;++i){ 57 | cl = hm->buckets[i]; 58 | while(cl != NULL){ 59 | nl = cl->next; 60 | wr_mpool_free(hm->mpool ,cl); 61 | //free(cl); 62 | cl = nl; 63 | } 64 | } 65 | //free(hm->buckets); 66 | wr_mpool_free(hm->mpool ,hm->buckets); 67 | } while(0); 68 | 69 | memset(hm ,0 ,sizeof(*hm)); 70 | } 71 | 72 | int wr_hash_add(wr_hashmap *hm ,const void *key ,const void *value) 73 | { 74 | int pos = hm->hashfun(key) % hm->size; 75 | wr_hashlist * nhl = (wr_hashlist *)wr_mpool_malloc(hm->mpool ,sizeof(wr_hashlist)); 76 | //wr_hashlist * nhl = (wr_hashlist *)malloc(sizeof(wr_hashlist)); 77 | //if(hm->buckets[pos] == NULL) 78 | // ++hm->used; 79 | 80 | nhl->key = key,nhl->value=value; 81 | nhl->next= hm->buckets[pos]; 82 | hm->buckets[pos] = nhl; 83 | 84 | return pos; 85 | //++(hm->length); 86 | //printf(" %d" ,pos); 87 | //if(hm->length%8 == 0) printf("\n"); 88 | } 89 | 90 | void* wr_hash_find(const wr_hashmap *hm ,const void *key) 91 | { 92 | int pos = hm->hashfun(key) % hm->size; 93 | wr_hashlist *nlh = hm->buckets[pos]; 94 | void *ret = NULL; 95 | while(nlh != NULL){ 96 | if(hm->hashcmp(nlh->key ,key)){ 97 | ret = nlh->value; 98 | break; 99 | } 100 | nlh = nlh->next; 101 | } 102 | return ret; 103 | } 104 | 105 | /* 106 | 37-300 ,132 are ok 107 | 37-1025 852 are ok 108 | all is 37 ,used >= 34*/ 109 | int wr_hashfun_str(const char *s) 110 | { 111 | int even ,odd; 112 | int i = 0; 113 | int mask = 0x1F; 114 | int ret; 115 | even = odd = 0; 116 | while(*s != '\0'){ 117 | if(i&1) odd ^= *s; 118 | else even ^= *s; 119 | ++s; 120 | ++i; 121 | } 122 | //only last 5bit are consider 123 | ret = even&mask; 124 | ret <<= 5; 125 | ret += (odd&mask); 126 | return ret; 127 | } 128 | /* 129 | 37-300 ,110 are ok 130 | 37-1025 822 are ok 131 | all is 37 ,used >= 34*/ 132 | int wr_hashfun_prime(const char *s) 133 | { 134 | /*2 ,3 ,5 ,7 ,11 ,13 ,17,19,23,29,31*/ 135 | int primeflag[32]={ 136 | 0 ,0 ,1 ,1 ,0 ,1 ,0 ,1 , 137 | 0 ,0 ,0 ,1 ,0 ,1 ,0 ,0 , 138 | 0 ,1 ,0 ,1 ,0 ,0 ,0 ,1 , 139 | 0 ,0 ,0 ,0 ,0 ,1 ,0 ,1 140 | }; 141 | int mask = 0x1F; 142 | int i=0; 143 | int pValue = 0; 144 | int nValue=0; 145 | int ret; 146 | while(*s){ 147 | if(i<32 && primeflag[i]) pValue ^= *s; 148 | else nValue ^= *s; 149 | ++s; 150 | ++i; 151 | } 152 | ret = pValue&mask; 153 | ret <<= 5; 154 | ret += nValue&mask; 155 | 156 | return ret; 157 | } 158 | /* 159 | 37-300 ,127 are ok 160 | 37-1025 837 are ok 161 | all is 37 ,used >= 34*/ 162 | int wr_hashfun_elf(const char *s) 163 | { 164 | unsigned long h,g; 165 | h=0; 166 | while(*s){ 167 | h = (h<<4) + *s++; 168 | g = h & 0xf0000000; 169 | if(g) h ^= g>>24; 170 | h &= ~g; 171 | } 172 | return h; 173 | } 174 | 175 | -------------------------------------------------------------------------------- /src/httpserver/wrlib/wrhash.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __WR_HASH_H__ 3 | #define __WR_HASH_H__ 4 | 5 | #ifdef __cplusplus 6 | extern "C"{ 7 | #endif 8 | #include "wrstring.h" 9 | #include "wrmpool.h" 10 | 11 | typedef struct _slist{ 12 | void *key; 13 | void *value; 14 | struct _slist *next; 15 | }wr_hashlist; 16 | 17 | /* 18 | typedef struct{ 19 | void *key; 20 | void *value; 21 | }wr_pair; 22 | */ 23 | typedef struct{ 24 | wr_hashlist **buckets; 25 | size_t size; 26 | // int used; 27 | // int length; 28 | wr_mpool *mpool; 29 | int (*hashfun)(const void *key); 30 | int (*hashcmp)(const void *lkey ,const void *rkey); 31 | }wr_hashmap; 32 | 33 | void wr_hash_init(wr_hashmap* hm ,wr_mpool *mp ,size_t _size); 34 | void wr_hash_clear(wr_hashmap *hm); 35 | 36 | int wr_hash_add(wr_hashmap *hm ,const void *key ,const void *value); 37 | void* wr_hash_find(const wr_hashmap *hm ,const void *key); 38 | 39 | int wr_hashfun_elf(const char *s); 40 | int wr_hashfun_str(const char *s); 41 | 42 | static int wr_hashcmp_str(const char *s1 ,const char *s2) 43 | { 44 | return strcmp(s1 ,s2)==0 ; 45 | } 46 | 47 | static int wr_hashcasecmp_str(const char *s1 ,const char *s2) 48 | { 49 | return wr_strcasecmp(s1 ,s2)==0 ; 50 | } 51 | 52 | /*just return the first letter*/ 53 | static int wr_hashfun_uchar(const char *s) 54 | { 55 | return (unsigned char)(*s); 56 | } 57 | 58 | 59 | #ifdef __cplusplus 60 | } 61 | #endif 62 | #endif 63 | 64 | -------------------------------------------------------------------------------- /src/httpserver/wrlib/wrio.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 windyrobin 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | * 22 | * $Id: wrio.c 3/14/2009 windyrobin@Gmail.com nanjing china$ 23 | */ 24 | #include "wrio.h" 25 | #include "misc.h" 26 | #include "analysis.h" 27 | #include "wrstring.h" 28 | 29 | static int sendFileStreamPOSIX(const WrHttp *pHttp ,const char *filePath) 30 | { 31 | char buf[PAGE_SIZE]; 32 | int rSize; 33 | int ret; 34 | /*must add O_BINARY on windows ,it cause me dubug for 2hours ,fuck!!*/ 35 | int fd = open(filePath ,O_RDONLY|O_BINARY); 36 | assert(fd >=0); 37 | while((rSize =read(fd ,buf ,sizeof(buf))) > 0){ 38 | if((ret=wr_sock_nwrite(pHttp->sock ,buf ,rSize)) <0) 39 | break; 40 | //printf("rSize ,ret : %d, %d\n" ,rSize ,ret); 41 | } 42 | close(fd); 43 | //printf("WSAERRPR :%d\n" ,WSAGetLastError()); 44 | return ret; 45 | } 46 | 47 | #ifdef _WIN32 48 | static int sendFileStreamWin32(const WrHttp *pHttp ,const char *filePath) 49 | { 50 | HANDLE hFile; 51 | DWORD dwBytesRead; 52 | char buf[PAGE_SIZE]; 53 | int ret; 54 | 55 | hFile = CreateFile(filePath, // open ONE.TXT 56 | GENERIC_READ, // open for reading 57 | 0, // do not share 58 | NULL, // no security 59 | OPEN_EXISTING, // existing file only 60 | FILE_ATTRIBUTE_NORMAL, // normal file 61 | NULL); // no attr. template 62 | 63 | if (hFile == INVALID_HANDLE_VALUE){ 64 | DBG("Could not open %s" ,filePath); // process error 65 | return -1; 66 | } 67 | do{ 68 | if (ReadFile(hFile, buf, sizeof(buf), &dwBytesRead, NULL)) { 69 | if((ret=wr_sock_nwrite(pHttp->sock ,buf ,dwBytesRead)) < 0) 70 | break; 71 | } 72 | } while (dwBytesRead == PAGE_SIZE); 73 | CloseHandle(hFile); 74 | return ret; 75 | } 76 | #endif 77 | 78 | /*send file stream ,if ok return the final send size ,else 79 | return last send error , 80 | maybe you want to rewrite the code use filemapping/mmap or 81 | win32 api ,here i just call POSIX interface! 82 | */ 83 | int sendFileStream(const WrHttp *pHttp ,const char *filePath) 84 | { 85 | #ifdef _WIN32 86 | return sendFileStreamWin32(pHttp ,filePath); 87 | #else 88 | return sendFileStreamPOSIX(pHttp ,filePath); 89 | #endif 90 | } 91 | 92 | /*if EINTR ,try once*/ 93 | static int wr_sock_recv(SOCKET sock ,char *buf ,size_t bufsize) 94 | { 95 | int ret; 96 | do { 97 | ret = recv(sock ,buf ,bufsize ,0); 98 | }while(ret<0 && WR_SOCK_ERRNO == EINTR); 99 | return ret; 100 | } 101 | 102 | /*read exactly n bytes , 103 | if ok return n 104 | else retrun -1 105 | here we use macro recv-timeout defined in http.h*/ 106 | 107 | int wr_sock_nread(SOCKET sock ,char *buf, size_t bufsize ,size_t n) 108 | { 109 | size_t nRead = 0; 110 | size_t nLeft = n; 111 | int ret; 112 | assert(bufsize >= n); 113 | while(nLeft > 0){ 114 | ret =wr_sock_recv(sock ,buf+nRead ,MIN(nLeft,WR_TCP_QUAN)); 115 | /*socket closed or error occurred*/ 116 | if(ret <= 0) 117 | break; 118 | else{ 119 | nRead += ret; 120 | nLeft -= ret; 121 | } 122 | } 123 | return nRead==n ? n : -1; 124 | } 125 | 126 | /*if ok return n ,else 127 | return -1*/ 128 | int wr_sock_nwrite(SOCKET sock ,char *buf ,size_t n) 129 | { 130 | size_t nLeft = n; 131 | size_t nWrite =0; 132 | int ret; 133 | while(nLeft > 0){ 134 | ret =send(sock ,buf+nWrite ,nLeft ,0); 135 | /*socket closed or error occurred*/ 136 | if(ret==0 || (ret<0 && WR_SOCK_ERRNO != EINTR)) 137 | break; 138 | else{ 139 | nLeft -= ret; 140 | nWrite += ret; 141 | } 142 | } 143 | return nWrite==n ? n : -1; 144 | } 145 | 146 | /* 147 | \r\n\r\n or \n\n ,they can be separated in any position!! 148 | @pBuf the data buf 149 | @cPos current-check begin pos 150 | @len len to be checked(from cPos) 151 | if OK return i>=0 152 | else return -1 153 | */ 154 | static int isHeadEnd(char *pBuf ,char *cPos ,int len) 155 | { 156 | int i=-1; 157 | while(++i < len){ 158 | if('\n' == *cPos){ 159 | if( (cPos-1>=pBuf && '\n'==*(cPos-1)) || \ 160 | (cPos-2>=pBuf && '\r'==*(cPos-1) && '\n'==*(cPos-2)) ){ 161 | return i; 162 | } 163 | } 164 | ++cPos; 165 | } 166 | return -1; 167 | } 168 | 169 | /*if read head ok return nread 170 | if some error occurred ,return -1*/ 171 | int wr_read_head(SOCKET sock ,char *buf ,size_t bufsize) 172 | { 173 | int nRead = 0; 174 | int rsize; 175 | int flag = -1; 176 | do { 177 | rsize = wr_sock_recv(sock ,buf+nRead ,bufsize-nRead); 178 | if(rsize <=0) 179 | break; 180 | flag = isHeadEnd(buf ,buf+nRead ,rsize); 181 | nRead += rsize; 182 | }while(flag < 0); 183 | 184 | return (flag <0) ? -1 : nRead; 185 | } 186 | 187 | /*if error occurred ,return -1, 188 | and send http-400 ,bad request, 189 | */ 190 | int wr_load_body(WrHttp *pHttp) 191 | { 192 | /*!!note ,we shouldn't decode querystring or post data here 193 | for they may contain character like '&', '=', or something like that*/ 194 | int ret; 195 | int cLen ,rLen ,sLen; 196 | const char *pType ,*pLen; 197 | do{ 198 | /*"x-www-form-urlencoded"*/ 199 | pType = get_head_info(pHttp ,"Content-Type"); 200 | pLen = get_head_info(pHttp ,"Content-Length"); 201 | 202 | if(pType == NULL || pLen == NULL){ 203 | ret = -1; 204 | break;//error 205 | } 206 | /*content len*/ 207 | cLen = atoi(pLen); 208 | if(cLen<= 0 || cLen >MAX_POST_SIZE){ 209 | ret = -2; 210 | break;//error 211 | } 212 | /*len we required (include head)*/ 213 | rLen = pHttp->curPos - pHttp->method + cLen; 214 | /*content len we have got*/ 215 | sLen = pHttp->recvLen - (pHttp->curPos-pHttp->method); 216 | 217 | DBG("cLen ,rLen ,sLen: %d %d %d\n" ,cLen ,rLen ,sLen); 218 | if(cLen == sLen){ 219 | DBG("just ok..\n"); 220 | pHttp->postData = pHttp->curPos; 221 | ret = 1; 222 | }else if(cLen >sLen){ 223 | /*pre recv buf is too short to hold the content we require 224 | so we should read socket again 225 | !!note ,you must check pHttp->postData==pHttp->curPos otherwise 226 | you should free it*/ 227 | if(cLen + pHttp->curPos - pHttp->method > MAX_HEADER_SIZE){ 228 | pHttp->postData = malloc(cLen+8); 229 | memmove(pHttp->postData ,pHttp->curPos ,sLen); 230 | } 231 | ret = wr_sock_nread(pHttp->sock ,pHttp->postData + sLen ,cLen-sLen ,cLen-sLen); 232 | if(cLen-sLen == ret){ 233 | ret = 2; 234 | }else 235 | ret = -3; 236 | }else{ 237 | ret = -4; 238 | } 239 | }while(0); 240 | if(ret >0){ 241 | pHttp->paramEndPos = pHttp->postData + cLen; 242 | *(pHttp->paramEndPos) = '\0'; 243 | } 244 | DBG("contentType : %d\n" ,ret); 245 | return ret; 246 | } 247 | 248 | -------------------------------------------------------------------------------- /src/httpserver/wrlib/wrio.h: -------------------------------------------------------------------------------- 1 | 2 | #include "http.h" 3 | 4 | #ifndef __WR_IO_H__ 5 | #define __WR_IO_H__ 6 | 7 | #ifdef __cplusplus 8 | extern "C"{ 9 | #endif 10 | 11 | int wr_sock_nwrite(SOCKET sock ,char *buf ,size_t n); 12 | 13 | int wr_read_head(SOCKET sock ,char *buf ,size_t bufsize); 14 | int wr_load_body(WrHttp *pHttp); 15 | int sendFileStream(const WrHttp *pHttp ,const char *filePath); 16 | 17 | #ifdef __cplusplus 18 | } 19 | #endif 20 | 21 | #endif 22 | 23 | -------------------------------------------------------------------------------- /src/httpserver/wrlib/wrmpool.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 windyrobin 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | * 22 | * $Id: wrmpool.c 3/18/2009 windyrobin@Gmail.com nanjing china$ 23 | */ 24 | #include 25 | #include 26 | #include "wrmpool.h" 27 | 28 | void wr_mpool_init(wr_mpool *pmp ,char *begin ,size_t len) 29 | { 30 | pmp->begin=begin; 31 | pmp->len = len; 32 | pmp->index = 0; 33 | pmp->cflag = 0; 34 | } 35 | 36 | void *wr_mpool_malloc(wr_mpool *pmp ,size_t mlen) 37 | { 38 | void *ret = NULL; 39 | int rIndex = pmp->index + mlen; 40 | if(rIndex > pmp->len){ 41 | ret = malloc(mlen); 42 | pmp->cflag = 1; 43 | }else{ 44 | ret = pmp->begin + pmp->index; 45 | pmp->index = rIndex; 46 | } 47 | return ret; 48 | } 49 | 50 | void wr_mpool_free(wr_mpool *pmp ,void *p) 51 | { 52 | /*only free when is allocated in heap*/ 53 | if(p < pmp->begin || p>=pmp->begin + pmp->len){ 54 | free(p); 55 | } 56 | } 57 | 58 | void wr_mpool_clear(wr_mpool *pmp) 59 | { 60 | pmp->index = 0; 61 | pmp->cflag = 0; 62 | } 63 | -------------------------------------------------------------------------------- /src/httpserver/wrlib/wrmpool.h: -------------------------------------------------------------------------------- 1 | #ifndef __WR_MPOOL_H__ 2 | #define __WR_MPOOL_H__ 3 | 4 | #ifdef __cplusplus 5 | extern "C"{ 6 | #endif 7 | 8 | typedef struct{ 9 | char *begin;/*start pos*/ 10 | size_t len;/*capacity*/ 11 | int index;/*curIndex*/ 12 | int cflag;/*clear flag ,when capacity isn't enough and call malloc ,you must set it to 1*/ 13 | }wr_mpool; 14 | 15 | void wr_mpool_init(wr_mpool *pmp ,char *begin ,size_t len); 16 | void *wr_mpool_malloc(wr_mpool *pmp ,size_t mlen); 17 | void wr_mpool_free(wr_mpool *pmp ,void *p); 18 | void wr_mpool_clear(wr_mpool *pmp); 19 | 20 | #ifdef __cplusplus 21 | } 22 | #endif 23 | #endif 24 | 25 | -------------------------------------------------------------------------------- /src/httpserver/wrlib/wrstring.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 windyrobin 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | * 22 | * $Id: wrstring.c 3/14/2009 windyrobin@Gmail.com nanjing china$ 23 | */ 24 | 25 | #include 26 | #include 27 | 28 | /* add '\0' in token pos , 29 | * change pBuf to next pos 30 | */ 31 | 32 | /*we have define macro SKIP to replace it 33 | 34 | void skip(char **ppBuf ,char token) 35 | { 36 | char *pBuf = *ppBuf; 37 | while (*pBuf != token){ 38 | ++pBuf; 39 | } 40 | *pBuf = '\0'; 41 | *ppBuf = ++pBuf; 42 | } 43 | */ 44 | 45 | /**/ 46 | int wr_strcasecmp(register const char *lStr ,register const char *rStr) 47 | { 48 | while(*lStr && *rStr){ 49 | if(*lStr !=*rStr && tolower(*lStr)!=tolower(*rStr)) 50 | break; 51 | ++lStr; 52 | ++rStr; 53 | } 54 | return *lStr - *rStr; 55 | } 56 | /* 57 | int endscmp(const char *src ,const char *substr) 58 | { 59 | int llen = strlen(src); 60 | int rlen = strlen(substr); 61 | if(rlen 2 | #include "mf_socket.h" 3 | #include "mf_controller.h" 4 | #include "mf_logger.h" 5 | #include "stdio.h" 6 | #include "dbg.h" 7 | #include 8 | 9 | //uint32_t listen_sockfd = 0; 10 | static void print_info() 11 | { 12 | printf("\n\n -=Welcome to Microflow=-\n"); 13 | printf(" -=PanZhang dazhangpan@gmail.com=-\n"); 14 | printf(" -=WebUI://localhost:8000=-\n"); 15 | } 16 | 17 | void print_other() 18 | { 19 | printf("To quit, type \033[1m'quit'\033[m"); 20 | printf("\n"); 21 | } 22 | 23 | void print_welcome() 24 | { 25 | print_info(); 26 | printf(" \033[31m __ __ _ ______ _ \n\033[0m"); 27 | printf(" \033[31m| \\/ (_) | ____| | \n\033[0m"); 28 | printf(" \033[31m| \\ / |_ ___ _ __ ___ | |__ | | _____ __\n\033[0m"); 29 | printf(" \033[31m| |\\/| | |/ __| '__/ _ \\| __| | |/ _ \\ \\ /\\ / /\n\033[0m"); 30 | printf(" \033[31m| | | | | (__| | | (_) | | | | (_) \\ V V / \n\033[0m"); 31 | printf(" \033[31m|_| |_|_|\\___|_| \\___/|_| |_|\\___/ \\_/\\_/ \n\033[0m"); 32 | print_other(); 33 | } 34 | 35 | 36 | 37 | int main(int argc, char** argv) 38 | { 39 | char buf[32]; 40 | print_welcome(); 41 | controller_start(); 42 | while(scanf("%s", buf) > 0) 43 | { 44 | if(strcmp("quit", buf) == 0) 45 | break; 46 | } 47 | controller_exit(); 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /src/mf_api.h: -------------------------------------------------------------------------------- 1 | #ifndef MF_API_H__ 2 | #define MF_API_H__ 3 | 4 | #include "mf_socket.h" 5 | #include "mf_topomgr.h" 6 | #include "mf_devicemgr.h" 7 | #include "mf_msg_parser.h" 8 | #include "mf_timer.h" 9 | #include "mf_msg_handler.h" 10 | #include "./httpserver/cgi.h" 11 | //#include "mf_controller.h" 12 | 13 | void mf_controller_init() 14 | { 15 | parse_thread_start(WORKER_THREADS_NUM); 16 | start_stopwatch_thread(); 17 | mf_devicemgr_create(); 18 | mf_topomgr_create(); 19 | msg_handlers_init(); 20 | wr_init(); 21 | } 22 | 23 | void register_msg_handler(enum MSG_HANDLER_TYPE type, msg_handler_func func) 24 | { 25 | msg_handler_func_register(type, func); 26 | } 27 | 28 | void unregister_msg_handler(enum MSG_HANDLER_TYPE type, msg_handler_func func) 29 | { 30 | msg_handler_func_unregister(type, func); 31 | } 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/mf_controller.c: -------------------------------------------------------------------------------- 1 | #include "mf_controller.h" 2 | #include "mf_socket.h" 3 | #include "mf_logger.h" 4 | #include "dbg.h" 5 | #include "mf_wrapper.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | uint32_t listen_sockfd; 13 | extern void* handler_connection(void*); 14 | 15 | void controller_init(struct mf_controller * controller, char * name); 16 | { 17 | memcpy(controller->controller_name, name, sizeof(*name)); 18 | controller->port = 0; 19 | controller->configFile = NULL; 20 | controller->logFile = NULL; 21 | controller->bindaddr= NULL; 22 | controller->sock_fd= 0; 23 | } 24 | 25 | void controller_start() 26 | { 27 | set_CPU_instruction(); 28 | mf_logger_open(mf_default_log_path); 29 | listen_sockfd = mf_listen_socket_create(); 30 | mf_socket_bind(listen_sockfd); 31 | //mf_controller_init(); 32 | signal(SIGPIPE,SIG_IGN); 33 | pthread_t thread_id[NET_RECEIVE_WORKER_NUMBER]; 34 | int i = 0; 35 | for(; i < NET_RECEIVE_WORKER_NUMBER; i++) 36 | { 37 | if((pthread_create(&thread_id[i], 0, handle_connection, (void*)(&listen_sockfd))) < 0) 38 | { 39 | log_err("thread create error"); 40 | exit(0); 41 | } 42 | pthread_detach(thread_id[i]); 43 | } 44 | } 45 | 46 | void controller_exit() 47 | { 48 | mf_logger_close(); 49 | mf_topomgr_destroy(); 50 | mf_devicemgr_destroy(); 51 | log_info("Microflow exit"); 52 | } 53 | -------------------------------------------------------------------------------- /src/mf_controller.h: -------------------------------------------------------------------------------- 1 | #ifndef __MF_CONTROLLER_H__ 2 | #define __MF_CONTROLLER_H__ 3 | #include "mf_socket.h" 4 | #include "mf_topomgr.h" 5 | #include "mf_devicemgr.h" 6 | //#include "mf_api.h" 7 | 8 | #define NET_RECEIVE_WORKER_NUMBER 1 9 | #define MAX_NAME_LENGTH 32 10 | #define IP_ADDR_LENGTH 4 11 | 12 | struct mf_controller 13 | { 14 | char controller_name[MAX_NAME_LENGTH]; 15 | char * configFile; 16 | char * logFile; 17 | int port; /* TCP listening port */ 18 | char * bindaddr[IP_ADDR_LENGTH]; /* Addresses we should bind to */ 19 | int sock_fd; 20 | }; 21 | 22 | void controller_init(struct mf_controller * controller, char * name); 23 | void controller_start(); 24 | void controller_exit(); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/mf_devicemgr.c: -------------------------------------------------------------------------------- 1 | #include "mf_devicemgr.h" 2 | #include "dbg.h" 3 | #include "mf_switch.h" 4 | #include "mf_utilities.h" 5 | #include 6 | #include 7 | #include 8 | 9 | /*================= 10 | static Global variables 11 | ==================*/ 12 | 13 | struct mf_devicemgr MF_DEVICE_MGR; 14 | 15 | static struct host_hash_value * HOST_HASH_MAP[HOST_HASH_MAP_SIZE]; 16 | 17 | static struct host_hash_value HOST_CACHE_ARRAY[MAX_HOST_NUM]; 18 | 19 | /*================ 20 | Functions 21 | ==================*/ 22 | 23 | static void push_to_array(struct host_hash_value * value, struct host_hash_value ** array); 24 | static struct host_hash_value* hash_value_created(struct mf_switch *sw, uint32_t port_num, uint64_t mac_addr); 25 | static uint8_t if_host_exist(struct host_hash_value * value, struct mf_switch * sw, uint32_t port_num, uint64_t mac_addr); 26 | static void used_to_available(struct host_hash_value * value); 27 | 28 | void mf_devicemgr_create() 29 | { 30 | MF_DEVICE_MGR.total_switch_number = 0; 31 | pthread_mutex_init(&(MF_DEVICE_MGR.devicemgr_mutex), NULL); 32 | MF_DEVICE_MGR.switches.next = NULL; 33 | MF_DEVICE_MGR.switches.mark = 0; 34 | int i = 0; 35 | MF_DEVICE_MGR.used_list.next = NULL; 36 | MF_DEVICE_MGR.used_list.mark = 0; 37 | MF_DEVICE_MGR.available_list.next = NULL; 38 | MF_DEVICE_MGR.available_list.mark= 0; 39 | for(i = 0; i < MAX_HOST_NUM; i++) 40 | { 41 | lf_list_insert(&(HOST_CACHE_ARRAY[i].mem_manage_list), &(MF_DEVICE_MGR.available_list)); 42 | } 43 | MF_DEVICE_MGR.available_slot_num = i; 44 | MF_DEVICE_MGR.used_slot_num = 0; 45 | } 46 | 47 | void mf_devicemgr_destroy() 48 | { 49 | pthread_mutex_destroy(&(MF_DEVICE_MGR.devicemgr_mutex)); 50 | log_info("DEVICE manager destroyed"); 51 | } 52 | /*May return NULL 53 | Programmer should take care of this*/ 54 | struct mf_switch * get_switch(uint32_t sock) 55 | { 56 | return MF_DEVICE_MGR.mf_switch_map[sock]; 57 | } 58 | 59 | void add_switch(struct mf_switch* sw) 60 | { 61 | MF_DEVICE_MGR.mf_switch_map[sw->sockfd] = sw; 62 | lf_list_insert(&(sw->next_switch), &(MF_DEVICE_MGR.switches)); 63 | MF_DEVICE_MGR.total_switch_number++; 64 | } 65 | 66 | void delete_switch_from_map(struct mf_switch * sw) 67 | { 68 | pthread_mutex_lock(&sw->switch_mutex); 69 | MF_DEVICE_MGR.mf_switch_map[sw->sockfd] = NULL; 70 | MF_DEVICE_MGR.total_switch_number--; 71 | pthread_mutex_unlock(&sw->switch_mutex); 72 | lf_list_delete(&(sw->next_switch), &(MF_DEVICE_MGR.switches)); 73 | } 74 | /*The upper limit of agrument loop_index 75 | is decided by the the outer loop 76 | 77 | e.g. 78 | int i = 0; 79 | int intr_index = 0; 80 | for(i = 0; i < curr_sw_number; i++) 81 | { 82 | struct mf_switch * sw = get_next_switch(&intr_index); 83 | //Dosomething(sw); 84 | } 85 | This loop will return all the valid switches in the device manager storage. 86 | And execute the Dosomething function to all the switches. 87 | */ 88 | struct mf_switch * get_next_switch(int* loop_index) 89 | { 90 | if(*loop_index >= MAX_MF_SWITCH_NUM) 91 | { 92 | log_warn("Bad loop_index"); 93 | return NULL; 94 | } 95 | for(; *loop_index < MAX_MF_SWITCH_NUM; (*loop_index)++) 96 | { 97 | if(MF_DEVICE_MGR.mf_switch_map[*loop_index] != NULL) 98 | { 99 | if(*loop_index < MAX_MF_SWITCH_NUM - 1) 100 | { 101 | (*loop_index)++; 102 | return MF_DEVICE_MGR.mf_switch_map[(*loop_index) - 1]; 103 | } 104 | else 105 | { 106 | return MF_DEVICE_MGR.mf_switch_map[*loop_index]; 107 | } 108 | } 109 | } 110 | log_warn("No valid switch"); 111 | return NULL; 112 | } 113 | 114 | inline static struct mf_switch * get_next_switch_from_list(struct mf_switch * sw) 115 | { 116 | /*Keep the next_switch element at the top of struct mf_switch*/ 117 | struct lf_list * l = sw->next_switch.next; 118 | return (struct mf_switch*)l; 119 | } 120 | 121 | struct mf_switch * get_switch_by_dpid(uint64_t dpid) 122 | { 123 | int i,curr_index; 124 | curr_index = 0; 125 | for(i = 0; i < MF_DEVICE_MGR.total_switch_number; i++) 126 | { 127 | struct mf_switch* sw = get_next_switch(&curr_index); 128 | if(sw == NULL) 129 | { 130 | log_warn("No switch has this dpid"); 131 | return NULL; 132 | } 133 | else if(sw->datapath_id == dpid) 134 | { 135 | return sw; 136 | } 137 | } 138 | log_warn("No switch has this dpid"); 139 | return NULL; 140 | } 141 | 142 | struct mf_switch * get_switch_by_dpid_from_list(uint64_t dpid) 143 | { 144 | struct mf_switch * tmp = get_next_switch_from_list((struct mf_switch *) &(MF_DEVICE_MGR.switches)); 145 | while(tmp != NULL) 146 | { 147 | if(tmp->datapath_id == dpid) 148 | return tmp; 149 | else 150 | tmp = get_next_switch_from_list(tmp); 151 | } 152 | log_warn("No switch has this dpid:%ld", dpid); 153 | return NULL; 154 | } 155 | 156 | struct ofp11_port * get_switch_port_by_port_num(struct mf_switch* sw, ovs_be32 port_num) 157 | { 158 | pthread_mutex_lock(&sw->switch_mutex); 159 | if(unlikely(sw == NULL)) 160 | { 161 | log_warn("sw is NULL"); 162 | pthread_mutex_unlock(&sw->switch_mutex); 163 | return NULL; 164 | } 165 | int i = 0; 166 | for(; i < sw->port_num; i++) 167 | { 168 | if(sw->ports[i].port_no == port_num) 169 | { 170 | pthread_mutex_unlock(&sw->switch_mutex); 171 | return &(sw->ports[i]); 172 | } 173 | } 174 | pthread_mutex_unlock(&sw->switch_mutex); 175 | log_warn("No port has this port num"); 176 | return NULL; 177 | } 178 | 179 | struct host_hash_value* host_hash_value_add(struct mf_switch * sw, uint32_t port_num, uint64_t mac_addr) 180 | { 181 | uint64_t index = mac_addr_hash(mac_addr); 182 | struct host_hash_value * value = NULL; 183 | if(HOST_HASH_MAP[index] == NULL) 184 | { 185 | value = hash_value_created(sw, port_num, mac_addr); 186 | HOST_HASH_MAP[index] = value; 187 | value->hash_map_slot_index = index; 188 | value->is_occupied = 1; 189 | } 190 | else 191 | { 192 | struct lf_list * tmp = &(HOST_HASH_MAP[index]->hash_list); 193 | while(tmp) 194 | { 195 | struct host_hash_value * value = container_of(tmp, struct host_hash_value, hash_list); 196 | if(if_host_exist(value, sw, port_num, mac_addr)) 197 | { 198 | return NULL; 199 | } 200 | else 201 | { 202 | if(tmp->next== NULL) 203 | { 204 | value = hash_value_created(sw, port_num, mac_addr); 205 | lf_list_insert(&(value->hash_list),&(HOST_HASH_MAP[index]->hash_list)); 206 | value->hash_map_slot_index = index; 207 | value->is_occupied = 1; 208 | break; 209 | } 210 | else 211 | tmp = tmp->next; 212 | } 213 | } 214 | } 215 | return value; 216 | } 217 | 218 | static inline uint8_t if_host_exist(struct host_hash_value * value, struct mf_switch * sw, uint32_t port_num, uint64_t mac_addr) 219 | { 220 | return !((value->mac_addr ^ mac_addr) | ((unsigned long)value->sw ^ (unsigned long)sw) | (value->port_num ^ port_num)); 221 | } 222 | 223 | static struct host_hash_value* hash_value_created(struct mf_switch *sw, uint32_t port_num, uint64_t mac_addr) 224 | { 225 | struct lf_list * l = lf_list_pop(&MF_DEVICE_MGR.available_list); 226 | struct host_hash_value * value = container_of(l, struct host_hash_value, mem_manage_list); 227 | lf_list_insert(l, &(MF_DEVICE_MGR.used_list)); 228 | MF_DEVICE_MGR.available_slot_num--; 229 | MF_DEVICE_MGR.used_slot_num++; 230 | if(value != NULL) 231 | { 232 | value->mem_manage_list.next = NULL; 233 | value->mem_manage_list.mark = 0; 234 | value->hash_list.next = NULL; 235 | value->hash_list.mark = 0; 236 | value->sw = sw; 237 | lf_list_insert(&value->switch_list, &sw->hosts); 238 | value->port_num = port_num; 239 | value->mac_addr = mac_addr; 240 | return value; 241 | } 242 | log_warn("Value slot is NULL"); 243 | return NULL; 244 | } 245 | 246 | inline uint32_t mac_addr_hash(uint64_t key) 247 | { 248 | key = (~key) + (key << 21); // key = (key << 21) - key - 1; 249 | key = key ^ (key >> 24); 250 | key = (key + (key << 3)) + (key << 8); // key * 265 251 | key = key ^ (key >> 14); 252 | key = (key + (key << 2)) + (key << 4); // key * 21 253 | key = key ^ (key >> 28); 254 | key = key + (key << 31); 255 | return (key % HOST_HASH_MAP_SIZE); 256 | } 257 | 258 | struct mf_switch * get_switch_by_host_mac(uint64_t mac_addr) 259 | { 260 | uint32_t index = mac_addr_hash(mac_addr); 261 | if(HOST_HASH_MAP[index] == NULL) 262 | return NULL; 263 | else 264 | { 265 | struct lf_list * tmp = &(HOST_HASH_MAP[index]->hash_list); 266 | while(tmp) 267 | { 268 | struct host_hash_value * value = container_of(tmp, struct host_hash_value, hash_list); 269 | if(value->mac_addr == mac_addr) 270 | return value->sw; 271 | else 272 | { 273 | if(tmp->next) 274 | tmp = tmp->next; 275 | else 276 | return NULL; 277 | } 278 | } 279 | return NULL; 280 | } 281 | } 282 | 283 | 284 | //TODO: To test 285 | void delete_host_hash_value(struct host_hash_value * value, struct host_hash_value * bucket_head) 286 | { 287 | if(HOST_HASH_MAP[value->hash_map_slot_index] == NULL) 288 | { 289 | log_warn("value is not exist"); 290 | return; 291 | } 292 | struct host_hash_value * tmp = HOST_HASH_MAP[value->hash_map_slot_index]; 293 | struct lf_list * link = &(tmp->hash_list); 294 | while(tmp) 295 | { 296 | if(tmp == value) 297 | { 298 | break; 299 | } 300 | else 301 | { 302 | link = link->next; 303 | tmp = container_of(link, struct host_hash_value, hash_list); 304 | } 305 | } 306 | if(tmp == NULL) 307 | { 308 | log_warn("value is not exist"); 309 | return; 310 | } 311 | lf_list_delete(link, &(bucket_head->hash_list)); 312 | used_to_available(value); 313 | } 314 | 315 | static void used_to_available(struct host_hash_value * value) 316 | { 317 | struct lf_list * tmp = lf_list_delete(&(value->hash_list), &(MF_DEVICE_MGR.used_list)); 318 | lf_list_insert(tmp, &(MF_DEVICE_MGR.available_list)); 319 | } 320 | 321 | void print_switch_link(struct mf_switch *sw) 322 | { 323 | struct network_link* p = sw->link_list.head; 324 | while(p) 325 | { 326 | printf("sw_dpid: %ld\n ", p->src->sw->datapath_id); 327 | printf("src_sw_dpid:%ld, src_port_num: %d\n", p->src->sw->datapath_id, p->src->port->port_no); 328 | printf("dst_sw_dpid:%ld, dst_port_num: %d\n", p->dst->sw->datapath_id, p->dst->port->port_no); 329 | p = p->sw_link_next; 330 | } 331 | } 332 | 333 | void print_all_switches() 334 | { 335 | pthread_mutex_lock(&MF_DEVICE_MGR.devicemgr_mutex); 336 | int i = 0; 337 | log_info("-----another one--------"); 338 | int intr_index = 0; 339 | for(i = 0; i < MF_DEVICE_MGR.total_switch_number; i++) 340 | { 341 | struct mf_switch * sw = get_next_switch(&intr_index); 342 | if(sw == NULL) 343 | printf("sw is NULL\n"); 344 | else 345 | print_switch_link(sw); 346 | } 347 | pthread_mutex_unlock(&MF_DEVICE_MGR.devicemgr_mutex); 348 | } 349 | -------------------------------------------------------------------------------- /src/mf_devicemgr.h: -------------------------------------------------------------------------------- 1 | #ifndef __MF_DEVICEMGR_H__ 2 | #define __MF_DEVICEMGR_H__ 3 | 4 | #include "Openflow/types.h" 5 | #include 6 | #include "mf_lf_list.h" 7 | 8 | 9 | struct mf_switch; 10 | 11 | #define MAX_MF_SWITCH_NUM 4096 12 | 13 | #define MAX_HOST_NUM 4096 14 | 15 | #define HOST_MUTEX_SLOT_SIZE 8 16 | 17 | #define HOST_HASH_MAP_SIZE 2048 18 | 19 | struct mf_devicemgr 20 | { 21 | uint32_t total_switch_number; 22 | struct mf_switch * mf_switch_map[MAX_MF_SWITCH_NUM]; 23 | struct lf_list switches; 24 | pthread_mutex_t devicemgr_mutex; 25 | struct lf_list available_list; 26 | struct lf_list used_list; 27 | uint32_t available_slot_num; 28 | uint32_t used_slot_num; 29 | }; 30 | 31 | void mf_devicemgr_create(); 32 | 33 | void mf_devicemgr_destroy(); 34 | 35 | void add_switch(struct mf_switch * ); 36 | 37 | struct mf_switch * get_switch(uint32_t sock); 38 | 39 | void delete_switch_from_map(struct mf_switch *); 40 | 41 | struct mf_switch * get_next_switch(int* loop_index);//Usually used within a for-loop 42 | /* 43 | do_something for all the valid switches 44 | Code template: 45 | func() 46 | { 47 | unit32_t i,j; 48 | j = 0; 49 | pthread_mutex_lock(&MF_SWITCH_MAP.devicemgr_mutex); 50 | for(i = 0; i < MF_SWITCH_MAP.total_switch_number; i++) 51 | { 52 | struct mf_switch* sw = get_switch_next_(&j); 53 | check(sw); 54 | do_something(sw); 55 | } 56 | pthread_mutex_unlock(&MF_SWITCH_MAP.devicemgr_mutex); 57 | } 58 | */ 59 | 60 | struct mf_switch * get_switch_by_dpid(uint64_t dpid); 61 | struct mf_switch * get_switch_by_dpid_from_list(uint64_t); 62 | struct ofp11_port * get_switch_port_by_port_num(struct mf_switch* sw, ovs_be32 port_num); 63 | 64 | 65 | /* 66 | Hash map to store host information 67 | Key: Host mac address 68 | Value: struct host_hash_value 69 | */ 70 | struct host_hash_value 71 | { 72 | struct lf_list mem_manage_list; 73 | struct lf_list hash_list; 74 | struct lf_list switch_list; 75 | struct mf_switch * sw; 76 | uint32_t port_num; 77 | uint64_t mac_addr; 78 | uint32_t host_array_slot_index; 79 | uint32_t hash_map_slot_index; 80 | uint8_t is_occupied; 81 | }; 82 | 83 | struct host_hash_value* host_hash_value_add(struct mf_switch * sw, uint32_t port_num, uint64_t mac_addr); 84 | 85 | inline uint32_t mac_addr_hash(uint64_t mac_addr); 86 | 87 | struct mf_switch * get_switch_by_host_mac(uint64_t mac_addr); 88 | 89 | void host_hash_value_destory(struct host_hash_value* value); 90 | 91 | void delete_host_hash_value(struct host_hash_value * value, struct host_hash_value * bucket_head); 92 | 93 | void print_switch_link(struct mf_switch *); 94 | 95 | void print_all_switches(); 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /src/mf_lf_list.c: -------------------------------------------------------------------------------- 1 | #include "mf_lf_list.h" 2 | #include "dbg.h" 3 | #include "mf_utilities.h" 4 | #include 5 | #include 6 | #include 7 | void lf_list_insert(struct lf_list* i, struct lf_list* l) 8 | { 9 | i->next = NULL; 10 | struct lf_list * tmp; 11 | do 12 | { 13 | tmp = (l->next); 14 | i->next = tmp; 15 | }while(!__sync_bool_compare_and_swap(&(l->next), tmp, i)); 16 | } 17 | 18 | struct lf_list * lf_list_pop(struct lf_list *l) 19 | { 20 | struct lf_list * tmp; 21 | do 22 | { 23 | tmp = l->next; 24 | if(tmp == NULL) 25 | return NULL; 26 | }while(!__sync_bool_compare_and_swap(&(l->next), tmp, tmp->next)); 27 | tmp->next = NULL; 28 | return tmp; 29 | } 30 | 31 | 32 | struct lf_list * lf_list_delete(struct lf_list* i, struct lf_list* l) 33 | { 34 | struct lf_list * tmp; 35 | struct lf_list ** tmpp; 36 | again: 37 | do 38 | { 39 | tmp = l->next; 40 | tmpp = &(l->next); 41 | while(tmp) 42 | { 43 | if(tmp == i) 44 | { 45 | tmp->mark = 1; 46 | break; 47 | } 48 | else 49 | { 50 | tmpp = &(tmp->next); 51 | tmp = tmp->next; 52 | } 53 | } 54 | if(tmp == NULL) 55 | { 56 | log_warn("List node has already been deleted"); 57 | return NULL; 58 | } 59 | if((*((char*)tmpp + (int)OFFSETOF(struct lf_list, mark))) == 0x1) //mark of previous node is 1 60 | { 61 | goto again; 62 | } 63 | }while(!__sync_bool_compare_and_swap(tmpp, i, i->next)); 64 | tmp->mark = 0; 65 | return i; 66 | } 67 | 68 | struct lf_list * lf_list_search_node(struct lf_list* l, compare cmp, void* arg) 69 | { 70 | struct lf_list * tmp = l->next; 71 | while(tmp) 72 | { 73 | if(unlikely(tmp->mark == 1))//is being deleted 74 | { 75 | l->mark = 0; 76 | return NULL; 77 | } 78 | if(cmp(arg, tmp) == 1) 79 | { 80 | l->mark = 0; 81 | return tmp; 82 | } 83 | tmp = tmp->next; 84 | } 85 | return NULL ; 86 | } 87 | -------------------------------------------------------------------------------- /src/mf_lf_list.h: -------------------------------------------------------------------------------- 1 | #ifndef MF_LF_LIST_H__ 2 | #define MF_LF_LIST_H__ 3 | 4 | #include "Openflow/types.h" 5 | 6 | #define OFFSETOF(type, member) (size_t)&(((type*)0)->member) 7 | 8 | #define container_of(ptr, type, member) ({const typeof( ((type *)0)->member ) *__mptr = (ptr);(type *)((char *)__mptr - OFFSETOF(type,member));}) 9 | 10 | struct lf_list 11 | { 12 | struct lf_list * next; 13 | char mark; 14 | }; 15 | 16 | typedef int (*compare)(void*, struct lf_list*); 17 | 18 | void lf_list_insert(struct lf_list* i, struct lf_list* l); 19 | struct lf_list * lf_list_pop(struct lf_list *l); 20 | struct lf_list * lf_list_delete(struct lf_list* i, struct lf_list* l); 21 | struct lf_list * lf_list_search_node(struct lf_list* l, compare, void*); 22 | #endif 23 | -------------------------------------------------------------------------------- /src/mf_logger.c: -------------------------------------------------------------------------------- 1 | #include "mf_logger.h" 2 | #include "dbg.h" 3 | #include "mf_timer.h" 4 | #include "mf_utilities.h" 5 | 6 | #include 7 | #include 8 | 9 | FILE* MF_LOG_FILE; 10 | 11 | void mf_logger_open(const char* path) 12 | { 13 | if(path == NULL) 14 | { 15 | log_warn("Log path is not specific"); 16 | path = mf_default_log_path; 17 | } 18 | 19 | MF_LOG_FILE = fopen(path, "w"); 20 | if(MF_LOG_FILE == NULL) 21 | { 22 | log_err("File open failed"); 23 | exit(0); 24 | } 25 | pthread_mutex_init(&log_mutex, NULL); 26 | } 27 | 28 | void mf_write_log(char* msg) 29 | { 30 | pthread_mutex_lock(&log_mutex); 31 | if(unlikely(msg == NULL)) 32 | { 33 | log_warn("Log Msg is null"); 34 | } 35 | char* t = get_asctime(); 36 | if(fprintf(MF_LOG_FILE, "[%s]:%s\n", t, msg) < 0) 37 | { 38 | log_warn("Log write error"); 39 | } 40 | pthread_mutex_unlock(&log_mutex); 41 | } 42 | 43 | void mf_write_socket_log(char* msg, int socketfd) 44 | { 45 | pthread_mutex_lock(&log_mutex); 46 | if(msg == NULL) 47 | { 48 | log_warn("\nLog Msg is null"); 49 | } 50 | char* t = get_asctime(); 51 | if(fprintf(MF_LOG_FILE, "[%s]: %s\n", t, socketfd, msg) < 0) 52 | { 53 | log_warn("Socket log write error"); 54 | } 55 | pthread_mutex_unlock(&log_mutex); 56 | } 57 | 58 | void mf_logger_close() 59 | { 60 | fclose(MF_LOG_FILE); 61 | } 62 | -------------------------------------------------------------------------------- /src/mf_logger.h: -------------------------------------------------------------------------------- 1 | #ifndef __MF_LOGGER_H__ 2 | #define __MF_LOGGER_H__ 3 | 4 | #include 5 | #include 6 | 7 | #define mf_default_log_path "./microflow.log" 8 | extern FILE* MF_LOG_FILE; 9 | pthread_mutex_t log_mutex; 10 | 11 | void mf_logger_open(const char* path); 12 | void mf_write_log(char*); 13 | void mf_write_socket_log(char*, int); 14 | void mf_logger_close(); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/mf_mempool.c: -------------------------------------------------------------------------------- 1 | #include "mf_mempool.h" 2 | #include "dbg.h" 3 | #include "mf_logger.h" 4 | #include "mf_utilities.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define barrier() __asm__ __volatile__("":::"memory") 11 | 12 | static char queue_mem_pool[MF_QUEUE_NODE_MEMPOOL_SIZE][RX_PACKET_SIZE]; 13 | 14 | struct mf_queue_node_mempool * mf_queue_node_mempool_create() 15 | { 16 | struct mf_queue_node_mempool * mp = (struct mf_queue_node_mempool*)malloc(sizeof(*mp)); 17 | if(mp == NULL) 18 | { 19 | log_err("malloc failed"); 20 | exit(0); 21 | } 22 | memset(mp, 0, sizeof(*mp)); 23 | int i = 0; 24 | for( ; i< MF_QUEUE_NODE_MEMPOOL_SIZE; i++) 25 | { 26 | mp->node_pool[i].rx_packet = &queue_mem_pool[i][0]; 27 | } 28 | mp->head = &mp->node_pool[0]; 29 | mp->tail = &mp->node_pool[MF_QUEUE_NODE_MEMPOOL_SIZE - 1]; 30 | mp->pop = mp->head; 31 | mp->push = mp->head; 32 | return mp; 33 | } 34 | 35 | void push_queue_node_to_mempool(char* rx_buffer, uint16_t rx_length, struct mf_switch* sw, struct mf_queue_node_mempool* mp) 36 | { 37 | if(unlikely((mp->pop > mp->head && mp->push == mp->pop - 1) || (mp->pop == mp->head && mp->push == mp->tail))) 38 | { 39 | log_warn("Queue is full, drop length:%d", rx_length); 40 | return; 41 | } 42 | memcpy(mp->push->rx_packet,rx_buffer, rx_length); 43 | mp->push->packet_length = rx_length; 44 | mp->push->sw = sw; 45 | if(unlikely(mp->push == mp->tail)) 46 | mp->push = mp->head; 47 | else 48 | mp->push++; 49 | } 50 | 51 | struct q_node * pop_queue_node_from_mempool(struct mf_queue_node_mempool* mp) 52 | { 53 | struct q_node * qn; 54 | if(unlikely(mp->pop == mp->push)) 55 | return NULL; 56 | qn = mp->pop; 57 | if(unlikely(mp->pop == mp->tail)) 58 | mp->pop = mp->head; 59 | else 60 | mp->pop++; 61 | return qn; 62 | } 63 | -------------------------------------------------------------------------------- /src/mf_mempool.h: -------------------------------------------------------------------------------- 1 | #ifndef MF_MEMPOOL_H__ 2 | #define MF_MEMPOOL_H__ 3 | 4 | #include "mf_rx_queue.h" 5 | #include 6 | 7 | #define MF_QUEUE_NODE_MEMPOOL_SIZE 1024 8 | 9 | struct mf_queue_node_mempool 10 | { 11 | struct q_node node_pool[MF_QUEUE_NODE_MEMPOOL_SIZE]; 12 | struct q_node * pop; 13 | uint32_t p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15;//cache padding 14 | struct q_node * push; 15 | uint32_t p16,p17,p18,p19,p20,p21,p22,p23,p24,p25,p26,p27,p28,p29;//cache padding 16 | struct q_node * head; 17 | struct q_node * tail; 18 | }; 19 | 20 | 21 | struct mf_queue_node_mempool * mf_queue_node_mempool_create(); 22 | void push_queue_node_to_mempool(char* rx_buffer, uint16_t rx_length, struct mf_switch* sw, struct mf_queue_node_mempool* mp); 23 | struct q_node * pop_queue_node_from_mempool(struct mf_queue_node_mempool* mp); 24 | void free_memblock(struct q_node*, struct mf_queue_node_mempool* mp); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/mf_msg_handler.h: -------------------------------------------------------------------------------- 1 | #ifndef __MF_MSG_HANDLER__ 2 | #define __MF_MSG_HANDLER__ 3 | 4 | #include "mf_rx_queue.h" 5 | #include "mf_switch.h" 6 | 7 | 8 | enum MSG_HANDLER_TYPE{ 9 | HELLO_MSG_HANDLER_FUNC, 10 | ECHO_REQUEST_HANDLER_FUNC, 11 | FEATURE_REPLY_HANDLER_FUNC, 12 | PACKET_IN_MSG_HANDLER_FUNC 13 | }; 14 | 15 | 16 | typedef void (*msg_handler_func)(struct q_node*); 17 | /*Msg handler structure used to register defualt and customlized handler functions 18 | For each type of msg, a linked list of handler func pointors could be created and the 19 | certain type of msg will go through the whole list in order to satisfy certain requirements 20 | */ 21 | struct single_msg_handler 22 | { 23 | msg_handler_func handler_func; 24 | struct single_msg_handler * next; 25 | }; 26 | 27 | struct msg_handlers 28 | { 29 | struct single_msg_handler * hello_msg_handler_list_head; 30 | struct single_msg_handler * echo_request_handler_list_head; 31 | struct single_msg_handler * feature_reply_handler_list_head; 32 | struct single_msg_handler * packet_in_msg_handler_list_head; 33 | }; 34 | 35 | void msg_handler(uint8_t type, uint8_t version, struct q_node* qn); 36 | void hello_msg_handler(struct q_node*); 37 | void echo_request_handler(struct q_node* qn); 38 | void send_packet_out(struct q_node* qn, uint32_t xid, uint32_t buffer_id, void* data, uint32_t data_length); 39 | void send_multipart_port_request(struct q_node* qn); 40 | void feature_reply_handler(struct q_node* qn); 41 | void packet_in_msg_handler(struct q_node*); 42 | void multipart_reply_handler(struct q_node* qn); 43 | void port_status_msg_handler(struct q_node* qn); 44 | void send_flow_mod(struct mf_switch * sw, uint32_t size); 45 | 46 | void arp_msg_handler(struct q_node* qn, uint32_t xid, char* buffer, uint16_t total_len); 47 | void lldp_msg_handler(struct q_node* qn, uint32_t xid, char* buffer, uint16_t total_len); 48 | 49 | void msg_handlers_init(); //register default msg hander func to MSG_HANDLERS 50 | struct single_msg_handler * single_msg_handler_create(msg_handler_func); 51 | void msg_handler_func_register(enum MSG_HANDLER_TYPE, msg_handler_func); 52 | void msg_handler_func_unregister(enum MSG_HANDLER_TYPE, msg_handler_func); 53 | #endif 54 | -------------------------------------------------------------------------------- /src/mf_msg_parser.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "mf_msg_parser.h" 8 | #include "mf_msg_handler.h" 9 | #include "mf_logger.h" 10 | #include "mf_rx_queue.h" 11 | #include "mf_switch.h" 12 | #include "mf_socket.h" 13 | #include "mf_mempool.h" 14 | #include "mf_utilities.h" 15 | #include "dbg.h" 16 | #include "./Openflow/openflow.h" 17 | #include "./Openflow/openflow-common.h" 18 | 19 | int queue_index[WORKER_THREADS_NUM]; 20 | 21 | void * worker_thread(void* arg) 22 | { 23 | set_cpu_affinity(); 24 | int index = *(int*)arg; 25 | while(1) 26 | { 27 | struct q_node * qn = pop_queue_node_from_mempool(MSG_RX_QUEUE[index]); 28 | if(unlikely(qn == NULL))// Maybe most of the time the queue is empty, but still treat the 'real' working branch as the primary branch 29 | usleep(1); 30 | else 31 | parse_msg(qn); 32 | } 33 | } 34 | 35 | void parse_thread_start(uint8_t num) 36 | { 37 | int i; 38 | for(i = 0; i < num; i++) 39 | { 40 | pthread_t thread_id; 41 | queue_index[i] = i; 42 | if((pthread_create(&thread_id, NULL, worker_thread, (void*)&queue_index[i])) < 0) 43 | { 44 | log_err("thread create error"); 45 | exit(0); 46 | } 47 | pthread_detach(thread_id); 48 | } 49 | } 50 | 51 | static inline uint8_t parse_msg_type(struct q_node* qn) 52 | { 53 | uint8_t type = *(qn->rx_packet + 1); 54 | return type; 55 | } 56 | 57 | static inline uint8_t parse_msg_version(struct q_node* qn) 58 | { 59 | uint8_t version = *(qn->rx_packet); 60 | return version; 61 | } 62 | 63 | void parse_msg(struct q_node* qn) 64 | { 65 | msg_handler(*(qn->rx_packet + 1), *(qn->rx_packet), qn); 66 | } 67 | 68 | -------------------------------------------------------------------------------- /src/mf_msg_parser.h: -------------------------------------------------------------------------------- 1 | #ifndef __MF_MSG_PARSER__ 2 | #define __MF_MSG_PARSER__ 3 | 4 | #include "Openflow/types.h" 5 | 6 | struct q_node; 7 | 8 | void parse_thread_start(uint8_t num); 9 | 10 | void parse_msg(struct q_node* ); 11 | 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /src/mf_ofmsg_constructor.c: -------------------------------------------------------------------------------- 1 | #include "mf_ofmsg_constructor.h" 2 | #include "mf_utilities.h" 3 | #include 4 | #include 5 | //#include "openflow-common.h" 6 | 7 | struct ofp_header ofp13_msg_header_constructor(uint32_t xid, uint8_t type, uint16_t length) 8 | { 9 | struct ofp_header oh; 10 | oh.version = 0x04; 11 | oh.type = type; 12 | oh.length = htons(length); 13 | oh.xid = xid; 14 | return oh; 15 | } 16 | 17 | struct ofp_header of13_hello_msg_constructor(uint32_t xid) 18 | { 19 | struct ofp_header of13_hello_msg; 20 | of13_hello_msg.version = 0x04; 21 | of13_hello_msg.type = 0x00; 22 | of13_hello_msg.length = htons(0x08); 23 | of13_hello_msg.xid = xid; 24 | return of13_hello_msg; 25 | } 26 | 27 | struct ofp_header of13_echo_reply_msg_constructor(uint32_t xid) 28 | { 29 | struct ofp_header of13_echo_reply_msg; 30 | of13_echo_reply_msg.version = 0x04; 31 | of13_echo_reply_msg.type = 0x03; 32 | of13_echo_reply_msg.length = htons(0x08); 33 | of13_echo_reply_msg.xid = xid; 34 | return of13_echo_reply_msg; 35 | } 36 | 37 | struct ofp_header of13_switch_feature_msg_constructor() 38 | { 39 | struct ofp_header of13_switch_feature_request_msg; 40 | of13_switch_feature_request_msg.version = 0x04; 41 | of13_switch_feature_request_msg.type = 0x05; 42 | of13_switch_feature_request_msg.length = htons(0x08); 43 | uint32_t xid = generate_random(); 44 | of13_switch_feature_request_msg.xid = xid; 45 | return of13_switch_feature_request_msg; 46 | } 47 | 48 | struct ofp11_packet_out of13_packet_out_msg_constructor(uint32_t buffer_id, uint16_t actions_len) 49 | { 50 | static struct ofp11_packet_out po; 51 | po.buffer_id = htonl(buffer_id); 52 | po.in_port = htonl(0xfffffffd); // OFPP_CONTROLLER 53 | po.actions_len = htons(actions_len); 54 | return po; 55 | } 56 | 57 | struct ofp_action_header ofp13_action_header_constructor(uint16_t type, uint16_t len) 58 | { 59 | struct ofp_action_header oah; 60 | oah.type = type; 61 | oah.len = len; 62 | return oah; 63 | } 64 | 65 | struct ofp_action_output ofp13_action_output_constructor(uint32_t port) 66 | { 67 | static struct ofp_action_output oao; 68 | oao.type = 0; 69 | oao.len = htons(16); 70 | oao.port = htonl(port); 71 | oao.max_len = 0; 72 | //bzero(&oao.pad, sizeof(oao.pad)); 73 | return oao; 74 | } 75 | 76 | 77 | struct ofp_multipart_request of13_multiaprt_request_constructor(uint16_t type, uint16_t flags) 78 | { 79 | static struct ofp_multipart_request omr; 80 | struct ofp_header oh; 81 | uint32_t xid = generate_random(); 82 | oh = ofp13_msg_header_constructor(xid, 18, 16); 83 | omr.header = oh; 84 | omr.type = htons(type); 85 | omr.flags = htons(flags); 86 | return omr; 87 | } 88 | 89 | struct ofp11_flow_mod of13_flow_mod_msg_constructor(uint8_t table_id, 90 | uint8_t command, 91 | ovs_be16 hard_timeout, 92 | ovs_be16 idle_timeout, 93 | ovs_be16 priority, 94 | ovs_be32 buffer_id, 95 | ovs_be16 flags) 96 | { 97 | struct ofp11_flow_mod flow_mod; 98 | flow_mod.cookie = 0; 99 | flow_mod.cookie_mask = 0; 100 | flow_mod.table_id = table_id; 101 | flow_mod.command = command; 102 | flow_mod.hard_timeout = hard_timeout; 103 | flow_mod.idle_timeout = idle_timeout; 104 | flow_mod.priority = priority; 105 | flow_mod.buffer_id = buffer_id; 106 | flow_mod.out_port = 0; 107 | flow_mod.out_group = 0; 108 | flow_mod.flags = flags; 109 | return flow_mod; 110 | } 111 | -------------------------------------------------------------------------------- /src/mf_ofmsg_constructor.h: -------------------------------------------------------------------------------- 1 | #ifndef __MF_OFMSG_CONSTRUCTOR__ 2 | #define __MF_OFMSG_CONSTRUCTOR__ 3 | 4 | #include "./Openflow/openflow-common.h" 5 | #include "./Openflow/openflow.h" 6 | 7 | struct ofp_header ofp13_msg_header_constructor(uint32_t xid, uint8_t type, uint16_t length); 8 | struct ofp_header of13_hello_msg_constructor(uint32_t xid); 9 | struct ofp_header of13_echo_reply_msg_constructor(uint32_t xid); 10 | struct ofp_header of13_switch_feature_msg_constructor(); 11 | struct ofp11_packet_out of13_packet_out_msg_constructor(uint32_t buffer_id, uint16_t actions_len); 12 | struct ofp_action_header ofp13_action_header_constructor(uint16_t type, uint16_t len); 13 | struct ofp_action_output ofp13_action_output_constructor(uint32_t port); 14 | struct ofp_multipart_request of13_multiaprt_request_constructor(uint16_t type, uint16_t flags); 15 | /*return the pointer of a flow_mod message*/ 16 | struct ofp11_flow_mod of13_flow_mod_msg_constructor(uint8_t table_id, 17 | uint8_t command, 18 | ovs_be16 hard_timeout, 19 | ovs_be16 idle_timeout, 20 | ovs_be16 priority, 21 | ovs_be32 buffer_id, 22 | ovs_be16 flags); 23 | 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/mf_rx_queue.c: -------------------------------------------------------------------------------- 1 | #include "mf_rx_queue.h" 2 | #include 3 | #include 4 | /* 5 | struct q_node* q_node_init(void* packet_buffer, uint16_t length, struct mf_switch* sw){ 6 | struct q_node* q = (struct q_node*)malloc(sizeof(struct q_node)); 7 | q->rx_packet = packet_buffer; 8 | q->packet_length = length; 9 | q->sw = sw; 10 | q->next_node = NULL; 11 | q->previous_node = NULL; 12 | return q; 13 | } 14 | 15 | struct mf_rx_queue* mf_rx_queue_init(){ 16 | struct mf_rx_queue* q = (struct mf_rx_queue*)malloc(sizeof(struct mf_rx_queue)); 17 | if(q == NULL){ 18 | printf("\nmalloc memory failed\n"); 19 | return NULL; 20 | }else{ 21 | q->queue_length = 0; 22 | q->head = NULL; 23 | q->tail = NULL; 24 | pthread_mutex_init(&(q->q_mutex), NULL); 25 | return q; 26 | } 27 | } 28 | 29 | uint8_t push_q_node(struct q_node* n, struct mf_rx_queue* q){ 30 | pthread_mutex_lock(&(q->q_mutex)); 31 | if(n == NULL || q == NULL) 32 | return 0; 33 | if(!q->queue_length){ 34 | q->head = n; 35 | q->tail = n; 36 | q->queue_length = 1; 37 | pthread_mutex_unlock(&(q->q_mutex)); 38 | return 1; 39 | } 40 | else if(q->queue_length > 0) 41 | { 42 | q->tail->next_node = n; 43 | n->previous_node = q->tail; 44 | n->next_node = NULL; 45 | q->tail = n; 46 | q->queue_length++; 47 | pthread_mutex_unlock(&(q->q_mutex)); 48 | return 1; 49 | } 50 | return 0; 51 | } 52 | 53 | struct q_node* pop_q_node(struct mf_rx_queue* q){ 54 | pthread_mutex_lock(&(q->q_mutex)); 55 | if(!q->queue_length || q->head == NULL) 56 | { 57 | pthread_mutex_unlock(&(q->q_mutex)); 58 | return NULL; 59 | } 60 | else 61 | { 62 | struct q_node* tmp = NULL; 63 | tmp = q->head; 64 | if(q->queue_length == 1) 65 | { 66 | q->head = NULL; 67 | q->tail = NULL; 68 | q->queue_length = 0; 69 | } 70 | else if(q->queue_length > 1) 71 | { 72 | q->head = tmp->next_node; 73 | q->head->previous_node = NULL; 74 | tmp->next_node = NULL; 75 | q->queue_length--; 76 | } 77 | else 78 | { 79 | pthread_mutex_unlock(&(q->q_mutex)); 80 | return NULL; 81 | } 82 | pthread_mutex_unlock(&(q->q_mutex)); 83 | return tmp; 84 | } 85 | } 86 | 87 | void destory_q_node(struct q_node* n){ 88 | if(n != NULL) 89 | if(n->rx_packet) 90 | free(n->rx_packet); 91 | free(n); 92 | } 93 | 94 | void destory_queue(struct mf_rx_queue* q){ 95 | pthread_mutex_lock(&(q->q_mutex)); 96 | if(q != NULL && q->head != NULL) 97 | { 98 | while(q->head) 99 | { 100 | struct q_node* tmp; 101 | tmp = q->head; 102 | q->head = tmp->next_node; 103 | destory_q_node(tmp); 104 | } 105 | q->queue_length = 0; 106 | pthread_mutex_unlock(&(q->q_mutex)); 107 | } 108 | else 109 | { 110 | pthread_mutex_unlock(&(q->q_mutex)); 111 | } 112 | free(q); 113 | } 114 | 115 | static void print_q_node(struct q_node* n){ 116 | char* content = (char*)(n->rx_packet); 117 | printf("Packet content:%s\n", content); 118 | } 119 | 120 | void print_queue(struct mf_rx_queue* q){ 121 | struct q_node* tmp; 122 | tmp = q->head; 123 | while(tmp){ 124 | print_q_node(tmp); 125 | tmp = tmp->next_node; 126 | } 127 | 128 | } 129 | */ 130 | 131 | -------------------------------------------------------------------------------- /src/mf_rx_queue.h: -------------------------------------------------------------------------------- 1 | #ifndef __MF_RX_QUEUE_H__ 2 | #define __MF_RX_QUEUE_H__ 3 | 4 | #include 5 | #include "./Openflow/types.h" 6 | #include 7 | 8 | #define RX_PACKET_SIZE 256 9 | 10 | struct mf_switch; 11 | 12 | struct q_node{ 13 | uint16_t packet_length; 14 | struct mf_switch* sw; 15 | char * rx_packet; 16 | uint8_t is_occupied; 17 | }; 18 | 19 | struct mf_rx_queue{ 20 | uint32_t queue_length; 21 | pthread_mutex_t q_mutex; 22 | struct q_node* head; 23 | struct q_node* tail; 24 | }; 25 | 26 | struct q_node* q_node_init(void* packet_buffer, uint16_t length, struct mf_switch* sw); 27 | struct mf_rx_queue* mf_rx_queue_init(); 28 | uint8_t push_q_node(struct q_node* n, struct mf_rx_queue* q); 29 | struct q_node* pop_q_node(struct mf_rx_queue*q ); 30 | void destory_q_node(struct q_node* n); 31 | void destory_queue(struct mf_rx_queue* q); 32 | void print_queue(struct mf_rx_queue* q); 33 | 34 | 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/mf_socket.c: -------------------------------------------------------------------------------- 1 | #include "mf_socket.h" 2 | #include "mf_logger.h" 3 | #include "mf_switch.h" 4 | #include "mf_rx_queue.h" 5 | #include "mf_mempool.h" 6 | #include "mf_utilities.h" 7 | #include "mf_api.h" 8 | #include "dbg.h" 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | struct sockaddr_in controller_addr, switch_addr; 23 | struct epoll_event ev, events[EPOLL_EVENTS_NUM]; 24 | struct mf_queue_node_mempool * MSG_RX_QUEUE[WORKER_THREADS_NUM]; 25 | uint32_t epfd, nfds; 26 | 27 | static void set_nonblocking(uint32_t sock) 28 | { 29 | int opts; 30 | opts=fcntl(sock,F_GETFL); 31 | if(opts<0) 32 | { 33 | log_err("fcntl(sock,GETFL)"); 34 | exit(1); 35 | } 36 | opts = opts|O_NONBLOCK; 37 | if(fcntl(sock,F_SETFL,opts)<0) 38 | { 39 | log_err("fcntl(sock,SETFL,opts)"); 40 | exit(1); 41 | } 42 | } 43 | 44 | 45 | uint32_t mf_listen_socket_create() 46 | { 47 | uint32_t sock; 48 | if((sock = socket(AF_INET, SOCK_STREAM,0)) == -1) 49 | { 50 | log_err("socket created failed"); 51 | exit(0); 52 | } 53 | int enable = 1; 54 | if(setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&enable, sizeof(enable)) != 0) 55 | { 56 | log_err("set sock option failed"); 57 | exit(0); 58 | } 59 | mf_write_socket_log("controller socket created",sock); 60 | return sock; 61 | } 62 | 63 | static void epoll_init(uint32_t sock) 64 | { 65 | epfd = epoll_create(1); 66 | ev.data.fd = sock; 67 | ev.events = EPOLLIN; 68 | epoll_ctl(epfd, EPOLL_CTL_ADD, sock, &ev); 69 | set_nonblocking(sock); 70 | listen(sock, SOMAXCONN); 71 | } 72 | 73 | 74 | void mf_socket_bind(uint32_t sock) 75 | { 76 | memset(&controller_addr, 0, sizeof(controller_addr)); 77 | controller_addr.sin_family = AF_INET; 78 | controller_addr.sin_addr.s_addr=htonl(INADDR_ANY); 79 | controller_addr.sin_port = htons(DEFAULT_PORT); 80 | if((bind(sock, (struct sockaddr*)&controller_addr,sizeof(controller_addr))) == -1) 81 | { 82 | log_err("socket bind failed"); 83 | exit(0); 84 | } 85 | mf_write_socket_log("socket binded with local IP addresses",sock); 86 | } 87 | 88 | 89 | void* handle_connection(void* arg) 90 | { 91 | uint32_t sock = *(uint32_t*)arg; 92 | set_cpu_affinity(); 93 | unsigned int i; 94 | int connfd; 95 | socklen_t clilen = sizeof(switch_addr); 96 | epoll_init(sock); 97 | static unsigned int seq = 0; 98 | for(i = 0; i < WORKER_THREADS_NUM; i++) 99 | { 100 | MSG_RX_QUEUE[i] = mf_queue_node_mempool_create(); 101 | } 102 | mf_controller_init(); 103 | while(1) 104 | { 105 | nfds = epoll_wait(epfd, events, EPOLL_EVENTS_NUM, -1); 106 | for(i = 0; i < nfds; i++) 107 | { 108 | if(events[i].data.fd == sock) 109 | { 110 | log_info("Incoming connection"); 111 | connfd = accept(sock, (struct sockaddr*)&switch_addr, &clilen); 112 | if(connfd < 0) 113 | { 114 | log_warn("connfd < 0"); 115 | continue; 116 | } 117 | mf_switch_create(connfd); 118 | ev.data.fd = connfd; 119 | ev.events = EPOLLIN; 120 | epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev); 121 | } 122 | else if(events[i].events & EPOLLIN) 123 | { 124 | int sockfd = events[i].data.fd; 125 | if(sockfd < 0) 126 | { 127 | log_warn("sockfd < 0"); 128 | continue; 129 | } 130 | struct mf_switch * sw = get_switch(sockfd); 131 | int length = read(sockfd, (char*)(sw->rx_buffer) + sw->epoll_recv_incomplete_length, RX_BUFFER_SIZE); 132 | if(length == 0) 133 | { 134 | ev.data.fd = sockfd; 135 | ev.events = EPOLLIN; 136 | epoll_ctl(epfd, EPOLL_CTL_DEL, sockfd, &ev); 137 | mf_switch_destory(sw); 138 | log_info("socket closed"); 139 | continue; 140 | } 141 | if(length < 0) 142 | { 143 | log_warn("socket error"); 144 | continue; 145 | } 146 | else if(likely(length > 0)) 147 | { 148 | char * pkt_ptr = sw->rx_buffer; 149 | length += sw->epoll_recv_incomplete_length; 150 | sw->epoll_recv_incomplete_length = 0; 151 | int received_length = length; 152 | while(likely(length > 0)) 153 | { 154 | if(likely((int)*pkt_ptr == 4))// This is a OF1.3 Msg 155 | { 156 | uint16_t msg_length = ntoh_16bit(pkt_ptr + 2); 157 | if(unlikely(length < msg_length)) 158 | { 159 | log_warn("received length is: %d,current length is: %d, msg length is %d",received_length, length, msg_length); 160 | sw->epoll_recv_incomplete_length = length; 161 | memmove(sw->rx_buffer, pkt_ptr, sw->epoll_recv_incomplete_length); 162 | break; 163 | } 164 | push_queue_node_to_mempool(pkt_ptr, msg_length, sw, MSG_RX_QUEUE[(seq) % WORKER_THREADS_NUM]); 165 | pkt_ptr += msg_length; 166 | length -= msg_length; 167 | } 168 | else 169 | { 170 | log_warn("Msg is not OF1.3"); 171 | log_warn("Packets drop, total length: %d", length); 172 | break; 173 | } 174 | } 175 | seq++; 176 | } 177 | } 178 | } 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /src/mf_socket.h: -------------------------------------------------------------------------------- 1 | #ifndef __MF_SOCKET_H__ 2 | #define __MF_SOCKET_H__ 3 | 4 | #include "./Openflow/types.h" 5 | 6 | #define DEFAULT_PORT 6633 7 | #define EPOLL_EVENTS_NUM 4096 8 | 9 | #define WORKER_THREADS_NUM 2 10 | 11 | #define RX_BUFFER_SIZE (16384* 32) 12 | 13 | struct mf_rx_queue; 14 | 15 | extern struct mf_queue_node_mempool * MSG_RX_QUEUE[WORKER_THREADS_NUM]; 16 | 17 | uint32_t mf_listen_socket_create(); 18 | void mf_socket_bind(uint32_t); 19 | void* handle_connection(void*); 20 | 21 | #endif 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/mf_switch.c: -------------------------------------------------------------------------------- 1 | #include "mf_switch.h" 2 | #include "mf_msg_parser.h" 3 | #include "mf_logger.h" 4 | #include "mf_devicemgr.h" 5 | #include "mf_rx_queue.h" 6 | #include "dbg.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | struct mf_switch * mf_switch_create(uint32_t sockfd) 13 | { 14 | struct mf_switch * sw = (struct mf_switch*)malloc(sizeof(struct mf_switch)); 15 | if(sw == NULL) 16 | { 17 | log_err("malloc failed"); 18 | exit(0); 19 | } 20 | sw->sockfd = sockfd; 21 | sw->epoll_recv_incomplete_length = 0; 22 | sw->datapath_id = 0; 23 | sw->n_buffers = 0; 24 | sw->n_tables = 0; 25 | sw->auxiliary_id = 0; 26 | sw->capabilities = 0; 27 | sw->port_num = 0; 28 | memset(&(sw->ports), 0, sizeof(sw->ports)); 29 | sw->is_hello_sent = 0; 30 | sw->is_feature_request_sent = 0; 31 | sw->is_port_desc_request_sent = 0; 32 | sw->feature_request_xid = 0; 33 | /*link_list has already been assigned an address*/ 34 | add_switch(sw); 35 | pthread_mutex_init(&(sw->switch_mutex), NULL); 36 | return sw; 37 | } 38 | 39 | void mf_switch_destory(struct mf_switch * sw) 40 | { 41 | if(sw == NULL) 42 | { 43 | log_warn("error: switch to destory is NULL"); 44 | //exit(0); 45 | return; 46 | } 47 | if(close(sw->sockfd) < 0) 48 | { 49 | log_warn("socket close error"); 50 | } 51 | delete_switch_from_map(sw); 52 | if(pthread_mutex_destroy(&sw->switch_mutex) < 0) 53 | log_warn("mutex destroy error"); 54 | free(sw); 55 | sw = NULL; 56 | } 57 | 58 | 59 | void switch_print(struct mf_switch * sw) 60 | { 61 | printf("sockfd:%d\n", sw->sockfd); 62 | printf("datapath_ID:%ld\n", sw->datapath_id); 63 | printf("port num:%d\n", sw->port_num); 64 | int i = 0; 65 | for(i = 0; i < sw->port_num; i++) 66 | { 67 | printf("Port %d: Port_no: %x\n", i, sw->ports[i].port_no); 68 | printf("Port %d: hardware addr: %x", i, (char)sw->ports[i].hw_addr[5]); 69 | printf(":%x", (char)sw->ports[i].hw_addr[4]); 70 | printf(":%x", (char)sw->ports[i].hw_addr[3]); 71 | printf(":%x", (char)sw->ports[i].hw_addr[2]); 72 | printf(":%x", (char)sw->ports[i].hw_addr[1]); 73 | printf(":%x\n", (char)sw->ports[i].hw_addr[0]); 74 | } 75 | } 76 | 77 | -------------------------------------------------------------------------------- /src/mf_switch.h: -------------------------------------------------------------------------------- 1 | #ifndef __MF_SWITCH_H__ 2 | #define __MF_SWITCH_H__ 3 | 4 | #include "mf_socket.h" 5 | #include "./Openflow/openflow-1.1.h" 6 | #include "mf_topomgr.h" 7 | #include 8 | #include "mf_lf_list.h" 9 | 10 | #define MAX_MF_SWITCH_PORT_NUM 256 11 | 12 | struct mf_switch 13 | { 14 | /*network switch list*/ 15 | /*Keep the next_switch element at the top of struct mf_switch*/ 16 | struct lf_list next_switch; 17 | /*--socket--*/ 18 | uint32_t sockfd; 19 | uint32_t epoll_recv_incomplete_length; 20 | /*--recv buffer--*/ 21 | char rx_buffer[RX_BUFFER_SIZE]; 22 | /*--openflow--*/ 23 | uint64_t datapath_id; 24 | uint32_t n_buffers; 25 | uint8_t n_tables; 26 | uint8_t auxiliary_id; 27 | uint32_t capabilities; 28 | uint16_t port_num; 29 | struct ofp11_port ports[MAX_MF_SWITCH_PORT_NUM]; 30 | /*--msg control--*/ 31 | uint8_t is_hello_sent; 32 | uint8_t is_feature_request_sent; 33 | uint8_t is_port_desc_request_sent; 34 | /*--transcation ids--*/ 35 | uint32_t feature_request_xid; 36 | /*--topo links --*/ 37 | struct sw_link_list link_list; 38 | /*--thread mutex--*/ 39 | pthread_mutex_t switch_mutex; 40 | /*hosts list*/ 41 | struct lf_list hosts; 42 | }; 43 | 44 | struct mf_switch * mf_switch_create(uint32_t sockfd); 45 | void mf_switch_destory(struct mf_switch *); 46 | 47 | /*For debug purpose*/ 48 | 49 | void switch_print(struct mf_switch *); 50 | 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/mf_timer.c: -------------------------------------------------------------------------------- 1 | #include "mf_timer.h" 2 | #include "dbg.h" 3 | #include 4 | #include "mf_rx_queue.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | struct stopwatch_list * MF_STOPWATCH_LIST; 12 | 13 | struct stopwatch * stopwatch_create(float sec, stopwatch_switch_callback swc, enum STOPWATCH_TYPE type, void* callback_arg) 14 | { 15 | struct stopwatch * stopwatch = (struct stopwatch*)malloc(sizeof(*stopwatch)); 16 | if(stopwatch == NULL) 17 | { 18 | log_err("malloc failed"); 19 | exit(0); 20 | } 21 | stopwatch->stop_sec = sec; 22 | stopwatch->time_remain = sec; 23 | stopwatch->type = type; 24 | stopwatch->next = NULL; 25 | stopwatch->sw_callback = swc; 26 | stopwatch->callback_arg = callback_arg; 27 | insert_stopwatch(stopwatch, MF_STOPWATCH_LIST); 28 | return stopwatch; 29 | } 30 | 31 | struct stopwatch_list * stopwatch_list_create() 32 | { 33 | struct stopwatch_list * swl = (struct stopwatch_list*)malloc(sizeof(*swl)); 34 | if(swl == NULL) 35 | { 36 | log_err("malloc failed"); 37 | exit(0); 38 | } 39 | swl->head = NULL; 40 | swl->stopwatch_num = 0; 41 | pthread_mutex_init(&swl->stopwatch_mutex, NULL); 42 | return swl; 43 | } 44 | 45 | void stopwatch_list_destory(struct stopwatch_list* swl) 46 | { 47 | if(swl == NULL) 48 | return; 49 | if(swl->head == NULL) 50 | { 51 | free(swl); 52 | return; 53 | } 54 | else 55 | { 56 | 57 | while(swl->head) 58 | { 59 | struct stopwatch * tmp = swl->head; 60 | swl->head = tmp->next; 61 | free(tmp); 62 | } 63 | free(swl); 64 | } 65 | } 66 | 67 | 68 | void insert_stopwatch(struct stopwatch* stopwatch, struct stopwatch_list* swl) 69 | { 70 | pthread_mutex_lock(&swl->stopwatch_mutex); 71 | if(swl->head == NULL) 72 | { 73 | swl->head = stopwatch; 74 | pthread_mutex_unlock(&swl->stopwatch_mutex); 75 | return; 76 | } 77 | else 78 | { 79 | struct stopwatch * tmp = swl->head; 80 | while(tmp->next) 81 | tmp = tmp->next; 82 | tmp->next = stopwatch; 83 | } 84 | pthread_mutex_unlock(&swl->stopwatch_mutex); 85 | } 86 | 87 | void stopwatch_countdown(struct stopwatch_list * swl) 88 | { 89 | //printf("stopwatch countdown\n"); 90 | pthread_mutex_lock(&swl->stopwatch_mutex); 91 | if(swl->head == NULL) 92 | { 93 | pthread_mutex_unlock(&swl->stopwatch_mutex); 94 | usleep(100000);//0.1 second 95 | return; 96 | } 97 | struct stopwatch * tmp; 98 | tmp = swl->head; 99 | while(tmp) 100 | { 101 | if(tmp->time_remain <= 0.0) 102 | { 103 | //printf("countdown to zero\n"); 104 | tmp->sw_callback(tmp->callback_arg); 105 | tmp->time_remain = tmp->stop_sec; 106 | } 107 | else 108 | { 109 | //printf("countdown by 0.1 seconds\n"); 110 | tmp->time_remain = tmp->time_remain - 0.1; 111 | } 112 | if(tmp->type == DISPOSIBILE) 113 | { 114 | //delete this stopwatch 115 | } 116 | tmp = tmp->next; 117 | } 118 | pthread_mutex_unlock(&swl->stopwatch_mutex); 119 | usleep(100000);//0.1 second 120 | } 121 | 122 | 123 | void* stopwatch_worker(void* arg) 124 | { 125 | //printf("stopwatch worker starts\n"); 126 | //struct q_node * qn = (struct q_node*)arg; 127 | while(1) 128 | { 129 | stopwatch_countdown(MF_STOPWATCH_LIST); 130 | } 131 | } 132 | 133 | void start_stopwatch_thread(struct q_node * qn) 134 | { 135 | MF_STOPWATCH_LIST = stopwatch_list_create(); 136 | pthread_t thread_id; 137 | if((pthread_create(&thread_id, NULL, stopwatch_worker, NULL)) < 0) 138 | { 139 | log_err("thread create error\n"); 140 | exit(0); 141 | } 142 | pthread_detach(thread_id); 143 | } 144 | 145 | char* get_asctime() 146 | { 147 | char* asc_time = NULL; 148 | time_t t; 149 | if(time(&t) < 0) 150 | { 151 | log_warn("get time error"); 152 | } 153 | asc_time = ctime(&t); 154 | char* tmp = asc_time; 155 | while(tmp) 156 | { 157 | if(*tmp == '\n') 158 | { 159 | *tmp = '\0'; 160 | break; 161 | } 162 | tmp++; 163 | } 164 | return asc_time; 165 | } 166 | -------------------------------------------------------------------------------- /src/mf_timer.h: -------------------------------------------------------------------------------- 1 | #ifndef __MF_TIMER_H__ 2 | #define __MF_TIMER_H__ 3 | 4 | #include 5 | #include 6 | #include "Openflow/types.h" 7 | 8 | struct mf_switch; 9 | 10 | enum STOPWATCH_TYPE 11 | { 12 | DISPOSIBILE, 13 | PERMANENT 14 | }; 15 | 16 | typedef void (*stopwatch_switch_callback)(void* ); 17 | 18 | struct stopwatch 19 | { 20 | float stop_sec; 21 | float time_remain; 22 | enum STOPWATCH_TYPE type; 23 | struct stopwatch * next; 24 | stopwatch_switch_callback sw_callback; 25 | void* callback_arg; 26 | }; 27 | 28 | struct stopwatch_list 29 | { 30 | struct stopwatch * head; 31 | uint8_t stopwatch_num; 32 | pthread_mutex_t stopwatch_mutex; 33 | }; 34 | 35 | extern struct stopwatch_list * MF_STOPWATCH_LIST; 36 | 37 | struct stopwatch * stopwatch_create(float sec, stopwatch_switch_callback,enum STOPWATCH_TYPE, void*); 38 | struct stopwatch_list * stopwatch_list_create(); 39 | void insert_stopwatch(struct stopwatch* stopwatch, struct stopwatch_list* swl); 40 | void stopwatch_list_destory(struct stopwatch_list*); 41 | void stopwatch_countdown(struct stopwatch_list *); 42 | void start_stopwatch_thread(); 43 | 44 | 45 | char* get_asctime(); 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /src/mf_topomgr.c: -------------------------------------------------------------------------------- 1 | #include "mf_topomgr.h" 2 | #include "mf_switch.h" 3 | #include "dbg.h" 4 | #include "mf_utilities.h" 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | static struct mf_topomgr MF_TOPO_MGR; 11 | 12 | static struct link_node * LINK_NODE_CACHE_ARRAY; 13 | 14 | static struct network_link NETWORK_LINK_CACHE_ARRAY[MAX_NETWORK_LINK_NUM]; 15 | 16 | static inline void push_to_array(struct link_node * value, struct link_node ** array); 17 | 18 | static inline struct link_node* pop_from_array(struct link_node * value, struct link_node ** array); 19 | 20 | void mf_topomgr_create() 21 | { 22 | MF_TOPO_MGR.total_node_number = 0; 23 | MF_TOPO_MGR.total_network_link_number = 0; 24 | MF_TOPO_MGR.node_cache_array_size = LINK_NODE_NUM; 25 | pthread_mutex_init(&(MF_TOPO_MGR.topomgr_mutex), NULL); 26 | LINK_NODE_CACHE_ARRAY = (struct link_node *)malloc(MF_TOPO_MGR.node_cache_array_size * sizeof(struct link_node)); 27 | if(LINK_NODE_CACHE_ARRAY == NULL) 28 | { 29 | log_err("topo mgr malloc failed\n"); 30 | exit(0); 31 | } 32 | memset(LINK_NODE_CACHE_ARRAY, 0 , MF_TOPO_MGR.node_cache_array_size * sizeof(*LINK_NODE_CACHE_ARRAY)); 33 | int i = 0; 34 | /* Network Node list*/ 35 | MF_TOPO_MGR.available_list.next = NULL; 36 | MF_TOPO_MGR.available_list.mark= 0; 37 | for(i = 0; i< MF_TOPO_MGR.node_cache_array_size; i++) 38 | lf_list_insert(&(LINK_NODE_CACHE_ARRAY[i].mem_manage_list), &(MF_TOPO_MGR.available_list)); 39 | MF_TOPO_MGR.used_list.next = NULL; 40 | MF_TOPO_MGR.used_list.mark= 0; 41 | /*Network link list*/ 42 | MF_TOPO_MGR.available_link_list.next = NULL; 43 | MF_TOPO_MGR.available_link_list.mark= 0; 44 | for(i = 0; i< MAX_NETWORK_LINK_NUM; i++) 45 | lf_list_insert(&(NETWORK_LINK_CACHE_ARRAY[i].mem_manage_list), &(MF_TOPO_MGR.available_link_list)); 46 | MF_TOPO_MGR.used_link_list.next= NULL; 47 | MF_TOPO_MGR.used_link_list.mark= 0; 48 | } 49 | 50 | void mf_topomgr_destroy() 51 | { 52 | if(LINK_NODE_CACHE_ARRAY) 53 | free(LINK_NODE_CACHE_ARRAY); 54 | pthread_mutex_destroy(&(MF_TOPO_MGR.topomgr_mutex)); 55 | log_info("TOPO manager destroyed"); 56 | } 57 | 58 | static void realloc_cache_array() 59 | { 60 | pthread_mutex_lock(&MF_TOPO_MGR.topomgr_mutex); 61 | LINK_NODE_CACHE_ARRAY = (struct link_node *)realloc(LINK_NODE_CACHE_ARRAY, 2 * MF_TOPO_MGR.node_cache_array_size * sizeof(struct link_node)); 62 | if(LINK_NODE_CACHE_ARRAY == NULL) 63 | { 64 | log_err("realloc cache array failed"); 65 | exit(0); 66 | } 67 | memset(LINK_NODE_CACHE_ARRAY + MF_TOPO_MGR.node_cache_array_size, 0, MF_TOPO_MGR.node_cache_array_size * sizeof(struct link_node)); 68 | pthread_mutex_unlock(&MF_TOPO_MGR.topomgr_mutex); 69 | int i; 70 | for(i = MF_TOPO_MGR.node_cache_array_size; i< MF_TOPO_MGR.node_cache_array_size * 2; i++) 71 | lf_list_insert(&(LINK_NODE_CACHE_ARRAY[i].mem_manage_list), &(MF_TOPO_MGR.available_list)); 72 | MF_TOPO_MGR.node_cache_array_size *= 2; 73 | } 74 | 75 | static struct link_node * get_available_value_slot() 76 | { 77 | if(MF_TOPO_MGR.available_list.next == NULL) 78 | realloc_cache_array(); 79 | struct lf_list* l = lf_list_pop(&MF_TOPO_MGR.available_list); 80 | struct link_node * value = container_of(l, struct link_node, mem_manage_list); 81 | lf_list_insert(l, &(MF_TOPO_MGR.used_list)); 82 | return value; 83 | } 84 | 85 | struct link_node * link_node_create(struct mf_switch* sw, struct ofp11_port* port) 86 | { 87 | if(port->node != NULL) 88 | { 89 | //log_warn("Node already exists"); 90 | return (port->node); 91 | } 92 | struct link_node * node = get_available_value_slot(); 93 | if(unlikely(node == NULL)) 94 | { 95 | log_warn("Bad value slot"); 96 | return NULL; 97 | } 98 | port->node= node; 99 | node->sw = sw; 100 | node->port = port; 101 | node->next = NULL; 102 | node->prev = NULL; 103 | node->is_occupied = 1; 104 | node->mem_manage_list.mark= 0;//Not necessary actually...But...Keep it as a good hobby.. 105 | MF_TOPO_MGR.total_node_number++; 106 | return node; 107 | } 108 | 109 | 110 | struct network_link * network_link_create(struct link_node* src, struct link_node* dst) 111 | { 112 | if(src->port->link != NULL) 113 | { 114 | return NULL; 115 | } 116 | struct lf_list * l = lf_list_pop(&(MF_TOPO_MGR.available_link_list)); 117 | if(l == NULL) 118 | { 119 | log_warn("No available slot"); 120 | return NULL; 121 | } 122 | struct network_link * link = container_of(l, struct network_link, mem_manage_list); 123 | lf_list_insert(l, &(MF_TOPO_MGR.used_link_list)); 124 | MF_TOPO_MGR.total_network_link_number++; 125 | link->src = src; 126 | src->port->link = link; 127 | link->dst = dst; 128 | link->sw_next.next = NULL; 129 | link->sw_next.mark = 0; 130 | lf_list_insert(l, &(MF_TOPO_MGR.used_link_list)); 131 | return link; 132 | } 133 | 134 | struct path_link_list * path_link_list_create() 135 | { 136 | struct path_link_list * list = (struct path_link_list *)malloc(sizeof(*list)); 137 | list->hop_num = 0; 138 | memset(&(list->path_link_list[0]), 0, sizeof(LONGEST_PATH_LINK_NUM * sizeof(struct network_link *))); 139 | return list; 140 | } 141 | 142 | uint32_t sw_link_insert(struct sw_link_list * sw_list, struct network_link * link) 143 | { 144 | if(unlikely(link == NULL)) 145 | { 146 | log_warn("link is NULL"); 147 | return 0; 148 | } 149 | pthread_mutex_lock(&(link->src->sw->switch_mutex)); 150 | if(sw_list->link_num == 0 && sw_list->head == NULL) 151 | { 152 | sw_list->head = link; 153 | } 154 | else 155 | { 156 | link->sw_link_next = sw_list->head; 157 | sw_list->head = link; 158 | } 159 | log_info("New network link discovered"); 160 | sw_list->link_num++; 161 | pthread_mutex_unlock(&(link->src->sw->switch_mutex)); 162 | return 1; 163 | } 164 | 165 | void network_path_insert(struct path_link_list * list, struct network_link * link) 166 | { 167 | if(list == NULL || link == NULL) 168 | return; 169 | if(list->hop_num == 0 && list->path_link_list[0] == NULL) 170 | { 171 | list->path_link_list[0] = link; 172 | } 173 | else 174 | { 175 | list->path_link_list[list->hop_num + 1] = link; 176 | } 177 | list->hop_num++; 178 | } 179 | 180 | void sw_link_delete(struct sw_link_list * list, struct network_link * link) 181 | { 182 | if(list == NULL || list->head == NULL) 183 | return; 184 | struct network_link * tmp = list->head; 185 | struct network_link * curr = NULL; 186 | while(tmp) 187 | { 188 | if(tmp == link) 189 | { 190 | if(tmp == list->head) 191 | { 192 | list->head = tmp->sw_link_next; 193 | list->link_num--; 194 | network_link_free(tmp); 195 | break; 196 | } 197 | else 198 | { 199 | curr->sw_link_next = tmp->sw_link_next; 200 | list->link_num--; 201 | network_link_free(tmp); 202 | break; 203 | } 204 | } 205 | curr = tmp; 206 | tmp = tmp->sw_link_next; 207 | } 208 | } 209 | 210 | void path_link_list_free(struct path_link_list * list) 211 | { 212 | if(list) 213 | free(list); 214 | } 215 | 216 | void network_link_free(struct network_link * link) 217 | { 218 | if(link->is_occupied == 1) 219 | link->is_occupied = 0; 220 | } 221 | 222 | /*code draft*/ 223 | /* 224 | struct path_link_list * find_one_path_between_switches(struct mf_switch * src_sw, struct mf_switch * dst_sw) 225 | { 226 | struct path_link_list * path = path_link_list_create(); 227 | int i = 0; 228 | char depth = 0; 229 | char search_depth[LONGEST_PATH_LINK_NUM] ; 230 | struct network_link * tmp = src_sw->link_list.head; 231 | for(;i <= src_sw->link_list.link_num; i++) 232 | { 233 | if(tmp->dst->sw == dst_sw) 234 | { 235 | path->path_link_list[depth] = tmp; 236 | return path; 237 | } 238 | else if(tmp == NULL) 239 | { 240 | depth--; 241 | tmp = 242 | } 243 | else 244 | { 245 | depth++; 246 | tmp = 247 | } 248 | } 249 | log_warn("Can not find a link between switch dpid:%ld and switch dpid:%ld", src_sw->datapath_id, dst_sw->datapath_id); 250 | return NULL; 251 | } 252 | */ 253 | -------------------------------------------------------------------------------- /src/mf_topomgr.h: -------------------------------------------------------------------------------- 1 | #ifndef MF_TOPOMGR_H__ 2 | #define MF_TOPOMGR_H__ 3 | #include "Openflow/types.h" 4 | #include "./Openflow/openflow-1.1.h" 5 | #include 6 | #include "mf_lf_list.h" 7 | 8 | 9 | struct mf_switch; 10 | 11 | #define MAX_NETWORK_LINK_NUM 4096 12 | #define MAX_NETWORK_LINK_NUM_PER_SWITCH 256 //identical to MAX SWITCH PORT NUM 13 | #define LONGEST_PATH_LINK_NUM 64 14 | #define LINK_NODE_NUM (MAX_NETWORK_LINK_NUM) * (2) 15 | 16 | struct mf_topomgr 17 | { 18 | uint64_t total_node_number; 19 | uint64_t total_network_link_number; 20 | uint64_t node_cache_array_size; 21 | pthread_mutex_t topomgr_mutex; 22 | struct lf_list available_list; 23 | struct lf_list used_list; 24 | struct lf_list available_link_list; 25 | struct lf_list used_link_list; 26 | }; 27 | 28 | struct link_node 29 | { 30 | struct lf_list mem_manage_list; //Keep this at the beginning of this structure 31 | struct link_node * next; //pointers for available/used slot bi-link list 32 | struct link_node * prev; 33 | struct mf_switch * sw; 34 | struct ofp11_port * port; 35 | uint8_t is_occupied; 36 | }; 37 | 38 | struct network_link 39 | { 40 | struct lf_list mem_manage_list; 41 | struct lf_list sw_next; 42 | struct link_node* src; 43 | struct link_node* dst; 44 | uint8_t is_occupied; 45 | struct network_link * sw_link_next; 46 | }; 47 | 48 | struct sw_link_list 49 | { 50 | uint16_t link_num; 51 | struct network_link * head; 52 | }; 53 | 54 | struct path_link_list 55 | { 56 | uint16_t hop_num; 57 | struct network_link * path_link_list[LONGEST_PATH_LINK_NUM]; 58 | }; 59 | 60 | void mf_topomgr_create(); 61 | void mf_topomgr_destroy(); 62 | struct link_node * link_node_create(struct mf_switch* sw, struct ofp11_port* port); 63 | struct network_link * network_link_create(struct link_node* src, struct link_node* dst); 64 | struct path_link_list * path_link_list_create(); 65 | uint32_t sw_link_insert(struct sw_link_list * list, struct network_link * link); 66 | void network_path_insert(struct path_link_list * list, struct network_link * link); 67 | void sw_link_delete(struct sw_link_list * list, struct network_link * link); 68 | void path_link_list_free(struct path_link_list * ); 69 | void network_link_free(struct network_link * link); 70 | struct path_link_list * find_one_path_between_switches(struct mf_switch * src_sw, struct mf_switch * dst_sw); 71 | 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /src/mf_utilities.c: -------------------------------------------------------------------------------- 1 | #include "mf_utilities.h" 2 | #include "mf_switch.h" 3 | #include "dbg.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | /*========================== 16 | Generate an uint32_t random number 17 | seed is the current system time(usec) 18 | ===========================*/ 19 | 20 | uint32_t generate_random() 21 | { 22 | struct timeval t; 23 | gettimeofday(&t, NULL); 24 | uint32_t r = rand_r((unsigned int *)&(t.tv_usec)); 25 | return r; 26 | } 27 | 28 | inline void mf_send(struct mf_switch * sw, void * msg, uint32_t length) 29 | { 30 | send(sw->sockfd, msg, length, MSG_DONTWAIT); 31 | } 32 | /*========================== 33 | Copy len byte of data from memory pointed 34 | by src inversely to memory pointed by dst 35 | e.g. src = "abcd", dst = "dcba" 36 | ===========================*/ 37 | inline void inverse_memcpy(void* dst, void* src, uint16_t len) 38 | { 39 | uint16_t i = 0; 40 | src = (char*)src + len - 1; 41 | while(i < len) 42 | { 43 | *(char*)dst++ = *(char*)src--; 44 | i++; 45 | } 46 | } 47 | 48 | inline uint16_t copy_16bit(char * ptr) 49 | { 50 | return *(uint16_t *)ptr; 51 | } 52 | 53 | inline uint32_t copy_32bit(char * ptr) 54 | { 55 | return *(uint32_t *)ptr; 56 | } 57 | 58 | inline uint64_t copy_64bit(char * ptr) 59 | { 60 | return *(uint64_t *)ptr; 61 | } 62 | 63 | inline uint32_t swap_32bit(uint32_t a) 64 | { 65 | uint32_t rst; 66 | asm("movl %1, %%eax;bswap %%eax;movl %%eax,%0;":"=r"(rst):"r"(a):"%eax"); 67 | return rst; 68 | } 69 | 70 | inline uint16_t swap_16bit(uint16_t a) 71 | { 72 | uint16_t rst; 73 | asm("mov %1, %%ax;xchg %%al, %%ah;mov %%ax, %0;":"=r"(rst):"r"(a):"%ah"); 74 | return rst; 75 | } 76 | 77 | inline uint16_t ntoh_16bit(char * ptr) 78 | { 79 | return swap_16bit(copy_16bit(ptr)); 80 | } 81 | 82 | inline uint32_t ntoh_32bit(char * ptr) 83 | { 84 | return swap_32bit(copy_32bit(ptr)); 85 | } 86 | 87 | inline uint64_t ntoh_64bit(char * ptr) 88 | { 89 | uint64_t r = (uint64_t)swap_32bit(copy_32bit(ptr))<< 32; 90 | return ( r | swap_32bit(copy_32bit(ptr + 4))); 91 | } 92 | 93 | 94 | void set_cpu_affinity() 95 | { 96 | int cpunum = sysconf(_SC_NPROCESSORS_ONLN); 97 | static char cpu_usage_flag[64]; 98 | if(cpunum >= 4) 99 | { 100 | int i = 0; 101 | for(; i < cpunum; i++) 102 | { 103 | if(cpu_usage_flag[i] == 0) 104 | { 105 | cpu_usage_flag[i] = 1; 106 | break; 107 | } 108 | } 109 | int ccpu_id = i; 110 | cpu_set_t my_set; 111 | CPU_ZERO(&my_set); 112 | CPU_SET(ccpu_id, &my_set); 113 | if(sched_setaffinity(0, sizeof(cpu_set_t), &my_set) == -1) 114 | log_warn("Set CPU affinity failed"); 115 | log_info("Set CPU Affinity of pthread:[%ld],to Core:[%d]",(long int)syscall(SYS_gettid), ccpu_id); 116 | } 117 | else 118 | log_info("Number of CPU cores is less than 4, Can not set CPU affinity"); 119 | } 120 | 121 | static UINT8 gn_htonll(UINT8 n) 122 | { 123 | return htonl(1) == 1 ? n : ((UINT8) htonl(n) << 32) | htonl(n >> 32); 124 | } 125 | 126 | void create_lldp_pkt(void *src_addr, UINT8 id, ovs_be32 port, lldp_t *buffer) 127 | { 128 | if(src_addr == NULL) 129 | return; 130 | UINT1 dest_addr[6] = {0x01,0x80,0xc2,0x00,0x00,0x0e}; 131 | 132 | memcpy(buffer->eth_head.dest,dest_addr,6); 133 | memcpy(buffer->eth_head.src, src_addr, 6); 134 | buffer->eth_head.proto = htons(0x88cc); 135 | 136 | buffer->chassis_tlv_type_and_len = htons(0x0209); 137 | buffer->chassis_tlv_subtype = LLDP_CHASSIS_ID_LOCALLY_ASSIGNED; 138 | buffer->chassis_tlv_id = gn_htonll(id); //datapath id 139 | 140 | buffer->port_tlv_type_and_len = htons(0x0403); 141 | buffer->port_tlv_subtype = LLDP_PORT_ID_COMPONENT; 142 | buffer->port_tlv_id = htons(port); //send port 143 | 144 | buffer->ttl_tlv_type_and_len = htons(0x0602); 145 | buffer->ttl_tlv_ttl = htons(120); 146 | 147 | /* 148 | buffer->orgspe_tlv_type_and_len = htons(0xfe0c); 149 | buffer->unique_code[0] = 0x00; 150 | buffer->unique_code[1] = 0x26; 151 | buffer->unique_code[2] = 0xe1; 152 | memcpy(buffer->sub_content, sub_content, 9); 153 | 154 | buffer->unknow1_tlv_type_and_len = htons(0x1808); 155 | buffer->unknow1_code = htonll(0x0baa92b47d87cbba); 156 | 157 | buffer->unknow2_tlv_type_and_len = htons(0xe601); 158 | buffer->unknow2_code = 0x01; 159 | */ 160 | 161 | buffer->endof_lldpdu_tlv_type_and_len = 0x00; 162 | } 163 | -------------------------------------------------------------------------------- /src/mf_utilities.h: -------------------------------------------------------------------------------- 1 | #ifndef MF_UTILITIES_H__ 2 | #define MF_UTILITIES_H__ 3 | 4 | #include "Openflow/types.h" 5 | struct mf_switch; 6 | /* 7 | program utilities 8 | */ 9 | uint32_t generate_random(); 10 | inline void inverse_memcpy(void* dst, void* src, uint16_t len); 11 | inline uint32_t swap_32bit(uint32_t); 12 | inline uint16_t swap_16bit(uint16_t); 13 | inline uint16_t copy_16bit(char * ptr); 14 | inline uint32_t copy_32bit(char * ptr); 15 | inline uint64_t copy_64bit(char * ptr); 16 | inline uint16_t ntoh_16bit(char * ptr); 17 | inline uint32_t ntoh_32bit(char * ptr); 18 | inline uint64_t ntoh_64bit(char * ptr); 19 | #define PTR_SUB(ptr, x) ((char*)ptr - (x)) 20 | #define PTR_ADD(ptr, x) ((char*)ptr + (x)) 21 | 22 | 23 | /* 24 | compiler utilities 25 | */ 26 | 27 | #define likely(x) __builtin_expect(!!(x), 1) 28 | #define unlikely(x) __builtin_expect(!!(x), 0) 29 | 30 | /* 31 | CPU utilities 32 | */ 33 | void set_cpu_affinity(); 34 | 35 | /* 36 | Network packets utilities 37 | */ 38 | 39 | inline void mf_send(struct mf_switch * sw, void * msg, uint32_t length); 40 | 41 | typedef signed char BOOL; 42 | typedef char INT1; 43 | typedef short INT2; 44 | typedef int INT4; 45 | typedef unsigned char UINT1; 46 | typedef unsigned short UINT2; 47 | typedef unsigned int UINT4; 48 | typedef unsigned int UINT; 49 | /* 50 | 64bit Linux OS only 51 | */ 52 | typedef long INT8; 53 | typedef unsigned long UINT8; 54 | 55 | #define MAX_PKT 1600 56 | 57 | 58 | enum ether_type 59 | { 60 | ETHER_LLDP = 0x88cc, 61 | ETHER_ARP = 0x0806, 62 | ETHER_IP = 0x0800, 63 | ETHER_IPV6 = 0x86DD, 64 | ETHER_VLAN = 0x8100, 65 | ETHER_MPLS = 0x8847 66 | }; 67 | enum lldp_tlv_type{ 68 | /* start of mandatory TLV */ 69 | LLDP_END_OF_LLDPDU_TLV = 0, 70 | LLDP_CHASSIS_ID_TLV = 1, 71 | LLDP_PORT_ID_TLV = 2, 72 | LLDP_TTL_TLV = 3, 73 | /* end of mandatory TLV */ 74 | /* start of optional TLV */ /*NOT USED */ 75 | LLDP_PORT_DESC_TLV = 4, 76 | LLDP_SYSTEM_NAME_TLV = 5, 77 | LLDP_SYSTEM_DESC_TLV = 6, 78 | LLDP_SYSTEM_CAPABILITY_TLV = 7, 79 | LLDP_MGMT_ADDR_TLV = 8 80 | /* end of optional TLV */ 81 | }; 82 | 83 | enum lldp_chassis_id_subtype { 84 | LLDP_CHASSIS_IP_MAC = 4, 85 | LLDP_CHASSIS_ID_LOCALLY_ASSIGNED = 7 86 | }; 87 | 88 | enum lldp_port_id_subtype { 89 | LLDP_PORT_ID_COMPONENT = 2, 90 | LLDP_PORT_ID_LOCALLY_ASSIGNED = 7 91 | }; 92 | 93 | #pragma pack(1) 94 | typedef struct st_ether 95 | { 96 | UINT1 dest[6]; 97 | UINT1 src[6]; 98 | UINT2 proto; 99 | UINT1 data[0]; 100 | }ether_t; 101 | 102 | typedef struct st_arp 103 | { 104 | ether_t eth_head; 105 | UINT2 hardwaretype; 106 | UINT2 prototype; 107 | UINT1 hardwaresize; 108 | UINT1 protocolsize; 109 | UINT2 opcode; 110 | UINT1 sendmac[6]; 111 | UINT4 sendip; 112 | UINT1 targetmac[6]; 113 | UINT4 targetip; 114 | UINT1 data[0]; 115 | }arp_t; 116 | 117 | typedef struct st_ip 118 | { 119 | ether_t eth_head; 120 | UINT1 hlen; 121 | UINT1 tos; 122 | UINT2 len; 123 | UINT2 ipid; 124 | UINT2 fragoff; 125 | UINT1 ttl; 126 | UINT1 proto; 127 | UINT2 cksum; 128 | UINT4 src; 129 | UINT4 dest; 130 | UINT1 data[0]; 131 | }ip_t; 132 | 133 | typedef struct st_tcp 134 | { 135 | UINT2 sport; 136 | UINT2 dport; 137 | UINT4 seq; 138 | UINT4 ack; 139 | UINT1 offset; 140 | UINT1 code; 141 | UINT2 window; 142 | UINT2 cksum; 143 | UINT2 urg; 144 | UINT1 data[0]; 145 | }tcp_t; 146 | 147 | typedef struct st_udp 148 | { 149 | UINT2 sport; 150 | UINT2 dport; 151 | UINT2 len; 152 | UINT2 cksum; 153 | UINT1 data[0]; 154 | }udp_t; 155 | 156 | typedef struct st_imcp 157 | { 158 | UINT1 type; 159 | UINT1 code; 160 | UINT2 cksum; 161 | UINT2 id; 162 | UINT2 seq; 163 | UINT1 data[0]; 164 | }icmp_t; 165 | 166 | typedef struct st_t802_1q 167 | { 168 | UINT2 proto; 169 | UINT2 vlan; 170 | UINT1 data[0]; 171 | }t802_1q_t; 172 | 173 | typedef struct st_dhcp 174 | { 175 | UINT1 opt; 176 | UINT1 htype; 177 | UINT1 hlen; 178 | UINT1 hops; 179 | UINT4 xid; 180 | UINT2 secd; 181 | UINT2 flg; 182 | UINT4 cipaddr; //client ip addr; 183 | UINT4 yipaddr; //you ip addr; 184 | UINT4 sipaddr; //server ip addr; 185 | UINT4 gipaddr; //agent ip addr; 186 | UINT1 cmcaddr[16]; 187 | UINT1 hostname[64]; 188 | UINT1 filename[128]; 189 | UINT4 sname; 190 | UINT1 data[0]; 191 | }dhcp_t; 192 | 193 | typedef struct st_tlv 194 | { 195 | UINT1 type; 196 | UINT1 len; 197 | char data[0]; 198 | }tlv_t; 199 | 200 | typedef struct st_dns_a 201 | { 202 | UINT2 label_ptr; 203 | UINT2 type; // type 204 | UINT2 clas; // class 205 | UINT4 ttl; 206 | UINT2 len; 207 | UINT1 data[0]; 208 | }dns_a_t; 209 | 210 | typedef struct st_dns_q 211 | { 212 | UINT1 len; 213 | char *data; 214 | }dns_q_t; 215 | 216 | typedef struct st_dns 217 | { 218 | UINT2 id; 219 | UINT2 flags; 220 | UINT2 questions; 221 | UINT2 answer; 222 | UINT2 author; 223 | UINT2 add; 224 | dns_q_t *dns_q; 225 | }dns_t; 226 | 227 | typedef struct st_ethpkt_info 228 | { 229 | UINT1 data[MAX_PKT]; 230 | UINT2 len; 231 | UINT2 vlan_id; 232 | INT4 qid; 233 | UINT1 ifindex; 234 | ether_t *pEth; 235 | ip_t *pIp; 236 | arp_t *pArp; 237 | tcp_t *pTcp; 238 | udp_t *pUdp; 239 | icmp_t *pIcmp; 240 | t802_1q_t *q8021q; 241 | }ethpkt_info_t; 242 | 243 | typedef struct st_lldp 244 | { 245 | ether_t eth_head; 246 | 247 | //9 Byte 248 | UINT2 chassis_tlv_type_and_len; //0x0207 249 | UINT1 chassis_tlv_subtype; //MAC 4 250 | UINT8 chassis_tlv_id; //dpid 251 | 252 | //5 Byte 253 | UINT2 port_tlv_type_and_len; //0x0403 254 | UINT1 port_tlv_subtype; //local assigned 7 255 | UINT2 port_tlv_id; //send port 256 | 257 | //4 Byte 258 | UINT2 ttl_tlv_type_and_len; //0x0602 259 | UINT2 ttl_tlv_ttl; //ttl 120 260 | 261 | //2 262 | UINT2 endof_lldpdu_tlv_type_and_len; 263 | }lldp_t; 264 | 265 | #pragma pack() 266 | 267 | void create_lldp_pkt(void *src_addr, UINT8 id, ovs_be32 port, lldp_t *buffer); 268 | 269 | #endif 270 | -------------------------------------------------------------------------------- /src/mf_wrapper.c: -------------------------------------------------------------------------------- 1 | #include "mf_wrapper.h" 2 | #include "dbg.h" 3 | 4 | /*cpuid function from Intel developer guide*/ 5 | static void __cpuid(unsigned int where[4], unsigned int leaf) 6 | { 7 | asm volatile("cpuid":"=a"(*where),"=b"(*(where+1)),"=c"(*(where+2)),"=d"(*(where+3)):"a" 8 | (leaf)); 9 | return; 10 | } 11 | 12 | /*Chech&set the instruction set of CPU*/ 13 | void set_CPU_instruction() 14 | { 15 | unsigned int cpuid_results[4]; 16 | __cpuid(cpuid_results,7); 17 | 18 | if(cpuid_results[1] &(1 << 16)) 19 | { 20 | #define RTE_MACHINE_CPUFLAG_AVX512F //comes from DPDK ^^ 21 | log_info("CPU Instruction set:AVX512F"); 22 | return; 23 | } 24 | if(cpuid_results[1] & (1 << 5)) 25 | { 26 | #define RTE_MACHINE_CPUFLAG_AVX2 27 | log_info("CPU Instruction set:AVX2"); 28 | return; 29 | } 30 | __cpuid(cpuid_results,1); 31 | if(cpuid_results[3] & (1 << 25)) 32 | log_info("CPU Instruction set:SSE"); 33 | } 34 | 35 | void mf_mov16(uint8_t * dst, const uint8_t * src) 36 | { 37 | __m128i xmm0; 38 | xmm0 = _mm_loadu_si128((const __m128i *)src); 39 | _mm_storeu_si128((__m128i *)dst, xmm0); 40 | } 41 | 42 | void mf_mov32(uint8_t * dst, const uint8_t *src) 43 | { 44 | mf_mov16((uint8_t *)dst + 0 * 16, (const uint8_t *)src + 0 * 16); 45 | mf_mov16((uint8_t *)dst + 1 * 16, (const uint8_t *)src + 1 * 16); 46 | } 47 | void mf_mov64(uint8_t * dst, const uint8_t *src) 48 | { 49 | mf_mov16((uint8_t *)dst + 0 * 16, (const uint8_t *)src + 0 * 16); 50 | mf_mov16((uint8_t *)dst + 1 * 16, (const uint8_t *)src + 1 * 16); 51 | mf_mov16((uint8_t *)dst + 2 * 16, (const uint8_t *)src + 2 * 16); 52 | mf_mov16((uint8_t *)dst + 3 * 16, (const uint8_t *)src + 3 * 16); 53 | } 54 | 55 | inline void mf_memcpy(void *dst, void *src, unsigned int n) 56 | { 57 | uint8_t * pdst = (uint8_t*)dst; 58 | uint8_t * psrc = (uint8_t*)src; 59 | while(n >= 8) 60 | { 61 | *(uint64_t *)pdst = *(uint64_t *)psrc; 62 | pdst += 8; 63 | psrc += 8; 64 | n -= 8; 65 | } 66 | if(n > 4) 67 | { 68 | *(uint32_t *)pdst = *(uint32_t *)psrc; 69 | pdst += 4; 70 | psrc += 4; 71 | n -= 4; 72 | } 73 | if(n > 2) 74 | { 75 | *(uint16_t *)pdst = *(uint16_t *)psrc; 76 | pdst += 2; 77 | psrc += 2; 78 | n -= 2; 79 | } 80 | if(n > 1) 81 | { 82 | *(uint16_t *)pdst = *(uint16_t *)psrc; 83 | //pdst += 2; 84 | //psrc += 2; 85 | //n -= 2; 86 | } 87 | } 88 | 89 | -------------------------------------------------------------------------------- /src/mf_wrapper.h: -------------------------------------------------------------------------------- 1 | #ifndef MF_WRAPPER_H__ 2 | #define MF_WRAPPER_H__ 3 | #include 4 | #include 5 | 6 | void set_CPU_instruction(); 7 | inline void mf_memcpy(void *dst, void *src, unsigned int n) __attribute__((always_inline)); 8 | void mf_mov16(uint8_t * dst, const uint8_t * src); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /src/minunit.h: -------------------------------------------------------------------------------- 1 | #undef NDEBUG 2 | #ifndef _minunit_h 3 | #define _minunit_h 4 | 5 | #include 6 | #include "dbg.h" 7 | #include 8 | 9 | #define mu_suite_start() char *message = NULL 10 | 11 | #define mu_assert(test, message) if (!(test)) { log_err(message); return message; } 12 | #define mu_run_test(test) debug("\n-----%s", " " #test); \ 13 | message = test(); tests_run++; if (message) return message; 14 | 15 | #define RUN_TESTS(name) int main(int argc, char *argv[]) {\ 16 | argc = 1; \ 17 | debug("----- RUNNING: %s", argv[0]);\ 18 | printf("----\nRUNNING: %s\n", argv[0]);\ 19 | char *result = name();\ 20 | if (result != 0) {\ 21 | printf("FAILED: %s\n", result);\ 22 | }\ 23 | else {\ 24 | printf("ALL TESTS PASSED\n");\ 25 | }\ 26 | printf("Tests run: %d\n", tests_run);\ 27 | exit(result != 0);\ 28 | } 29 | 30 | 31 | int tests_run; 32 | 33 | #endif -------------------------------------------------------------------------------- /tests/Makefile: -------------------------------------------------------------------------------- 1 | main.out: socket_test.c ../src/mf_socket.c ../src/mf_logger.c \ 2 | ../src/mf_timer.c ../src/mf_switch.c ../src/mf_msg_handler.c ../src/mf_ofmsg_constructor.c \ 3 | ../src/mf_devicemgr.c ../src/mf_rx_queue.c ../src/mf_msg_parser.c ../src/mf_mempool.c \ 4 | ../src/mf_utilities.c 5 | cc -g -Wall -D_GUN_SOURCE -D__USE_GUN -o $@ $^ -pthread 6 | 7 | clean: 8 | rm main.out 9 | -------------------------------------------------------------------------------- /tests/devicemgr.c: -------------------------------------------------------------------------------- 1 | #include "../src/mf_devicemgr.h" 2 | #include "../src/mf_switch.h" 3 | #include 4 | #include 5 | #include 6 | 7 | int main() 8 | { 9 | struct mf_switch * sw1 = mf_switch_create(4); 10 | struct mf_switch * sw2 = mf_switch_create(5); 11 | struct mf_switch * sw3 = mf_switch_create(6); 12 | struct mf_switch * sw4 = mf_switch_create(7); 13 | struct mf_switch * sw5 = mf_switch_create(8); 14 | struct mf_switch * sw6,sw7,sw8,sw9,sw10; 15 | mf_devicemgr_create(); 16 | add_switch(sw1); 17 | add_switch(sw2); 18 | add_switch(sw3); 19 | add_switch(sw4); 20 | add_switch(sw5); 21 | int i,j = 0; 22 | for(; i < 5; i++) 23 | { 24 | sw6 = get_next_switch(&j); 25 | } 26 | uint64_t mac1 = 11111111111; 27 | uint64_t mac2 = 1111111111; 28 | host_hash_value_add(sw6, 5, mac1); 29 | host_hash_value_add(sw6, 5, mac2); 30 | host_hash_value_add(sw6, 6, mac1); 31 | host_hash_value_add(sw6, 5, mac1); 32 | sw6->datapath_id = mac1; 33 | struct mf_switch * p = get_switch_by_dpid(mac1); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /tests/host_hash_test.c: -------------------------------------------------------------------------------- 1 | #include "../src/mf_devicemgr.h" 2 | #include "../src/mf_switch.h" 3 | 4 | int main() 5 | { 6 | uint64_t mac_addr1 = 0xacf01263b397; 7 | uint64_t mac_addr2 = 0x793b36210fca; 8 | uint32_t index1 = mac_addr_hash(mac_addr1); 9 | uint32_t index2 = mac_addr_hash(mac_addr2); 10 | struct mf_switch * sw1 = mf_switch_create(8); 11 | struct mf_switch * sw2 = mf_switch_create(9); 12 | mf_devicemgr_create(); 13 | //struct host_hash_value * pvalue1 = host_hash_value_create(sw1, 1, mac_addr1); 14 | //struct host_hash_value * pvalue2 = host_hash_value_create(sw2, 2, mac_addr2); 15 | //host_add_to_hash_map(pvalue1); 16 | //host_add_to_hash_map(pvalue1); 17 | //host_add_to_hash_map(pvalue2); 18 | host_hash_value_add(sw1, 6, mac_addr1); 19 | host_hash_value_add(sw1, 7, mac_addr1); 20 | host_hash_value_add(sw2, 7, mac_addr2); 21 | struct mf_switch * sw3 = get_switch_by_host_mac(mac_addr1); 22 | struct mf_switch * sw4 = get_switch_by_host_mac(mac_addr2); 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /tests/inverse_memcpy_test.c: -------------------------------------------------------------------------------- 1 | #include "../src/mf_utilities.h" 2 | #include 3 | #include 4 | 5 | uint32_t swap_32(uint32_t a) 6 | { 7 | uint32_t rst; 8 | asm("movl %1, %%eax;bswap %%eax;movl %%eax,%0;":"=r"(rst):"r"(a):"%eax"); 9 | return rst; 10 | } 11 | uint16_t swap_16(uint16_t a) 12 | { 13 | uint16_t rst; 14 | asm("mov %1, %%ax;xchg %%al, %%ah;mov %%ax, %0;":"=r"(rst):"r"(a):"%ah"); 15 | return rst; 16 | } 17 | uint16_t copy_16(char* ptr) 18 | { 19 | return *(uint16_t*)ptr; 20 | } 21 | 22 | int main() 23 | { 24 | time_t clockbegin, clockend; 25 | char * src_buffer = "abcdefghijk"; 26 | char dst_buffer[12]; 27 | inverse_memcpy(dst_buffer, src_buffer+2, 2); 28 | uint32_t test = 0x12345678; 29 | uint16_t test16 = 0x1234; 30 | uint64_t test64 = 0x1234567812345678; 31 | uint16_t test1 = ntoh_16bit(((char*)&test+1)); 32 | uint64_t test64_1 = ntoh_64bit(((char*)&test64)); 33 | printf("ntoh:%x\n",test1); 34 | printf("ntoh64:%ld\n",test64_1); 35 | uint32_t rst = swap_32(test); 36 | uint16_t rst_16 = swap_16(test16); 37 | printf("test:%x\n",rst); 38 | printf("test:%x\n",rst_16); 39 | int i = 0; 40 | time(&clockbegin); 41 | for(; i < 900000000; i++) 42 | inverse_memcpy(&test1, &test, 2); 43 | time(&clockend); 44 | printf("inverse_memcpy: %f\n", difftime(clockend, clockbegin)); 45 | time(&clockbegin); 46 | for(; i < 900000000; i++) 47 | test1 = ntoh_16bit(((char*)&test+1)); 48 | time(&clockend); 49 | printf("ntoh_swap: %f\n", difftime(clockend, clockbegin)); 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /tests/lock_free_list_test.c: -------------------------------------------------------------------------------- 1 | #include "../src/mf_lf_list.h" 2 | #include 3 | #include 4 | #include 5 | struct list_node 6 | { 7 | int val; 8 | struct lf_list list; 9 | }; 10 | 11 | struct list_node node_head = {888, {NULL, 0}}; 12 | int compare_list_node(void * arg, struct lf_list* n) 13 | { 14 | struct list_node *tmp =(struct list_node *)arg; 15 | //printf("tmp->val:%d\n", tmp->val); 16 | struct list_node * pln = container_of(n, struct list_node,list); 17 | //printf("pln->val:%d\n", pln->val); 18 | if(tmp->val == pln->val) 19 | { 20 | printf("val found : %d\n", tmp->val); 21 | return 1; 22 | } 23 | else 24 | return 0; 25 | } 26 | 27 | void print_list(struct lf_list* head) 28 | { 29 | struct lf_list* tmp = head; 30 | //printf("Print func\n"); 31 | while(tmp) 32 | { 33 | //printf("offset: %d\n", (int)OFFSETOF(struct list_node, list)); 34 | struct list_node * ptr = container_of(tmp, struct list_node, list); 35 | printf("val:%d\n",*(int*)((char*)tmp - OFFSETOF(struct list_node, list))); 36 | printf("val from ptr:%d\n", ptr->val); 37 | //printf("memory address: %x\n",(char)(tmp)); 38 | tmp = tmp->next; 39 | } 40 | 41 | } 42 | void * thread_func(void * arg) 43 | { 44 | //printf("Thread starts\n"); 45 | struct list_node * n = (struct list_node*)arg; 46 | //printf("input memory address: %x\n",(char)&n->list); 47 | lf_list_insert(&(n->list), &(node_head.list)); 48 | return NULL; 49 | } 50 | 51 | void * thread_func_pop(void * arg) 52 | { 53 | printf("pop_Thread starts\n"); 54 | struct lf_list * n = lf_list_pop(&(node_head.list)); 55 | struct list_node * ptr; 56 | printf("val:%d\n",*(int*)((char*)n - OFFSETOF(struct list_node, list))); 57 | return NULL; 58 | 59 | } 60 | 61 | void * thread_func_delete(void * arg) 62 | { 63 | struct list_node * n = (struct list_node *)arg; 64 | struct lf_list* t = lf_list_delete(&(n->list), &(node_head.list)); 65 | if(t != NULL) 66 | printf("delete val:%d\n",*(int*)((char*)t - OFFSETOF(struct list_node, list))); 67 | return NULL; 68 | } 69 | 70 | void * thread_func_search(void *arg) 71 | { 72 | lf_list_search_node(&(node_head.list),compare_list_node, arg); 73 | } 74 | int main() 75 | { 76 | struct list_node node1 = {1, {NULL,0}}; 77 | struct list_node node2 = {2, {NULL,0}}; 78 | struct list_node node3 = {3, {NULL,0}}; 79 | struct list_node node4 = {4, {NULL,0}}; 80 | struct list_node node5 = {5, {NULL,0}}; 81 | struct list_node nodes[5] = {node1, node2, node3, node4, node5}; 82 | pthread_t p[10]; 83 | int i = 0; 84 | /*for(i = 0; i < 5; i++) 85 | { 86 | pthread_create(&p[i], NULL, thread_func, &nodes[i]); 87 | } 88 | for(i = 0; i < 5; i++) 89 | { 90 | pthread_join(p[i],NULL); 91 | printf("Thread: %d ends\n",i); 92 | } 93 | print_list(&(node_head.list)); 94 | /* 95 | for(i = 5; i < 7; i++) 96 | { 97 | pthread_create(&p[i], NULL, thread_func_pop, &nodes[i-5]); 98 | } 99 | for(i = 5; i < 7; i++) 100 | { 101 | pthread_join(p[i],NULL); 102 | printf("Thread: %d ends\n",i); 103 | } 104 | */ 105 | // print_list(&(node_head.list)); 106 | for(i = 0; i < 10; i++) 107 | { 108 | if(i < 5) 109 | pthread_create(&p[i], NULL, thread_func, &nodes[i]); 110 | if(i < 7 && i >= 5) 111 | pthread_create(&p[i], NULL, thread_func_pop, &nodes[i-5]); 112 | if(i>=7 && i< 8) 113 | pthread_create(&p[i], NULL, thread_func_delete, &nodes[i-5]); 114 | if(i == 8 || i == 9) 115 | pthread_create(&p[i], NULL, thread_func_search, &nodes[i - 7]); 116 | } 117 | for(i = 0; i < 10; i++) 118 | { 119 | pthread_join(p[i],NULL); 120 | printf("Thread: %d ends\n",i); 121 | } 122 | print_list(&(node_head.list)); 123 | return 0; 124 | } 125 | -------------------------------------------------------------------------------- /tests/log_test.c: -------------------------------------------------------------------------------- 1 | #include "../src/mf_logger.h" 2 | #include "../src/mf_timer.h" 3 | 4 | //extern const char* mf_default_log_path; 5 | 6 | int main() 7 | { 8 | //printf("%s\n", get_asctime()); 9 | //mf_logger_open(mf_default_log_path); 10 | mf_logger_open(mf_default_log_path); 11 | mf_write_log("Test string.."); 12 | mf_write_log("another test string"); 13 | mf_logger_close(); 14 | return 0; 15 | } -------------------------------------------------------------------------------- /tests/queue_test.c: -------------------------------------------------------------------------------- 1 | /* file minunit_example.c */ 2 | #include 3 | #include "../src/minunit.h" 4 | #include "../src/mf_rx_queue.h" 5 | 6 | char* packet_content1 = "abcdefg"; 7 | char* packet_content2 = "higklmn"; 8 | char* packet_content3 = "opqrstu"; 9 | uint8_t packet_length = 8; 10 | 11 | 12 | static char* test_q_node_init(){ 13 | struct q_node* test = q_node_init(packet_content1, packet_length); 14 | printf("\nPacket_content:%s\n",(char*)(test->rx_packet)); 15 | mu_assert(test != NULL, "q_node_init_failed"); 16 | destory_q_node(test); 17 | return NULL; 18 | } 19 | 20 | static char* test_push_q_node(){ 21 | struct mf_rx_queue* queue = mf_rx_queue_init(); 22 | struct q_node* node1 = q_node_init(packet_content2, packet_length); 23 | //printf("\nPacket_content:%s\n",(char*)(node1->rx_packet)); 24 | mu_assert(push_q_node(node1, queue) == 1 ,"push queue failed"); 25 | struct q_node* node2 = q_node_init(packet_content3, packet_length); 26 | //printf("\nPacket_content:%s\n",(char*)(node2->rx_packet)); 27 | mu_assert(push_q_node(node2, queue) == 1 ,"push queue failed"); 28 | struct q_node* node3 = q_node_init(packet_content1, packet_length); 29 | mu_assert(push_q_node(node3, queue) == 1 ,"push queue failed"); 30 | print_queue(queue); 31 | return NULL; 32 | } 33 | 34 | static char* test_pop_q_node(){ 35 | struct mf_rx_queue* queue = mf_rx_queue_init(); 36 | struct q_node* node1 = q_node_init(packet_content2, packet_length); 37 | //printf("\nPacket_content:%s\n",(char*)(node1->rx_packet)); 38 | mu_assert(push_q_node(node1, queue) == 1 ,"push queue failed"); 39 | struct q_node* node2 = q_node_init(packet_content3, packet_length); 40 | //printf("\nPacket_content:%s\n",(char*)(node2->rx_packet)); 41 | mu_assert(push_q_node(node2, queue) == 1 ,"push queue failed"); 42 | struct q_node* node3 = q_node_init(packet_content1, packet_length); 43 | mu_assert(push_q_node(node3, queue) == 1 ,"push queue failed"); 44 | struct q_node* pop_node = pop_q_node(queue); 45 | mu_assert(pop_node != NULL,"pop queue failed"); 46 | mu_assert(queue->queue_length == 2, "bad length"); 47 | print_queue(queue); 48 | return NULL; 49 | } 50 | static char* test_destory_queue(){ 51 | struct mf_rx_queue* queue = mf_rx_queue_init(); 52 | struct q_node* node1 = q_node_init(packet_content2, packet_length); 53 | //printf("\nPacket_content:%s\n",(char*)(node1->rx_packet)); 54 | mu_assert(push_q_node(node1, queue) == 1 ,"push queue failed"); 55 | struct q_node* node2 = q_node_init(packet_content3, packet_length); 56 | //printf("\nPacket_content:%s\n",(char*)(node2->rx_packet)); 57 | mu_assert(push_q_node(node2, queue) == 1 ,"push queue failed"); 58 | struct q_node* node3 = q_node_init(packet_content1, packet_length); 59 | mu_assert(push_q_node(node3, queue) == 1 ,"push queue failed"); 60 | print_queue(queue); 61 | destory_queue(queue); 62 | } 63 | 64 | static char* test_handle_flow_mod() 65 | { 66 | 67 | //pfm = parser_flow_mod_msg(flow_mod_message); 68 | //printf("\n%d\n",ntohs(pfm.ofm.priority)); 69 | //mu_assert(init_flows() != NULL, "Init failed"); 70 | return NULL; 71 | } 72 | 73 | char *all_tests() 74 | { 75 | mu_suite_start(); 76 | mu_run_test(test_q_node_init); 77 | mu_run_test(test_push_q_node); 78 | mu_run_test(test_pop_q_node); 79 | mu_run_test(test_destory_queue); 80 | return NULL; 81 | } 82 | 83 | RUN_TESTS(all_tests); 84 | 85 | -------------------------------------------------------------------------------- /tests/socket_array_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../src/mf_socket_array.h" 3 | #include "../src/mf_socket.h" 4 | 5 | #define FIRST_SOCKET_FD 5 6 | #define SECOND_SOCKET_FD 6 7 | #define THIRD_SOCKET_FD 7 8 | 9 | int main(int argc, char** argv){ 10 | struct mf_socket s1 = mf_socket_create(FIRST_SOCKET_FD); 11 | struct mf_socket_array_node* n1 = mf_socket_array_node_init(s1); 12 | struct mf_socket_array * q = mf_socket_array_init(); 13 | insert_mf_socket_array(n1,q); 14 | struct mf_socket s2 = mf_socket_create(SECOND_SOCKET_FD); 15 | struct mf_socket_array_node* n2 = mf_socket_array_node_init(s2); 16 | insert_mf_socket_array(n2,q); 17 | struct mf_socket s3 = mf_socket_create(THIRD_SOCKET_FD); 18 | struct mf_socket_array_node* n3 = mf_socket_array_node_init(s3); 19 | insert_mf_socket_array(n3,q); 20 | delete_socket_array_node(SECOND_SOCKET_FD, q); 21 | return 0; 22 | } -------------------------------------------------------------------------------- /tests/socket_client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define MAXLINE 4096 10 | 11 | int main(int argc, char** argv) 12 | { 13 | int sockfd, n; 14 | char recvline[4096], sendline[4096]; 15 | struct sockaddr_in servaddr; 16 | int socket_fd_array[1000]; 17 | if( argc != 2){ 18 | printf("usage: ./client \n"); 19 | exit(0); 20 | } 21 | 22 | 23 | int i; 24 | for(i = 0; i < 10; i++) 25 | { 26 | if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){ 27 | printf("create socket error: %s(errno: %d)\n", strerror(errno),errno); 28 | exit(0); 29 | } 30 | socket_fd_array[i] = sockfd; 31 | 32 | memset(&servaddr, 0, sizeof(servaddr)); 33 | servaddr.sin_family = AF_INET; 34 | servaddr.sin_port = htons(6633); 35 | if( inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0){ 36 | printf("inet_pton error for %s\n",argv[1]); 37 | exit(0); 38 | } 39 | if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){ 40 | printf("connect error: %s(errno: %d)\n",strerror(errno),errno); 41 | exit(0); 42 | } 43 | char c[256] = "hello from a socket"; 44 | send(sockfd, c, sizeof(c), MSG_CONFIRM); 45 | usleep(100); 46 | } 47 | 48 | //sleep(2); 49 | for(i = 0; i < 10; i++) 50 | { 51 | close(socket_fd_array[i]); 52 | usleep(100); 53 | } 54 | 55 | return 0; 56 | } -------------------------------------------------------------------------------- /tests/socket_test.c: -------------------------------------------------------------------------------- 1 | #include "../src/mf_socket.h" 2 | #include "../src/mf_logger.h" 3 | #include 4 | 5 | 6 | int main(int argc, char** argv){ 7 | mallopt(M_ARENA_MAX, 1); 8 | mf_logger_open(mf_default_log_path); 9 | mf_write_log("--Test starts here--"); 10 | uint32_t s = mf_listen_socket_create(); 11 | mf_socket_bind(s); 12 | //char command[60]; 13 | handle_connection(s); 14 | mf_logger_close(); 15 | return 0; 16 | } -------------------------------------------------------------------------------- /tests/timer_test.c: -------------------------------------------------------------------------------- 1 | #include "../src/mf_timer.h" 2 | 3 | 4 | int main() 5 | { 6 | struct stopwatch * spw1 = stopwatch_create(5, NULL); 7 | struct stopwatch * spw2 = stopwatch_create(6, NULL); 8 | struct stopwatch * spw3 = stopwatch_create(7, NULL); 9 | struct stopwatch_list * swl = stopwatch_list_create(); 10 | insert_stopwatch(spw1,swl); 11 | insert_stopwatch(spw2,swl); 12 | insert_stopwatch(spw3,swl); 13 | stopwatch_countdown(NULL, swl); 14 | stopwatch_list_destory(swl); 15 | return 0; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /tests/topomgr_test.c: -------------------------------------------------------------------------------- 1 | #include "../src/mf_topomgr.h" 2 | #include "../src/mf_switch.h" 3 | 4 | int main() 5 | { 6 | mf_topomgr_create(); 7 | struct ofp11_port * sw1_port1; 8 | struct ofp11_port * sw1_port2; 9 | struct ofp11_port * sw2_port1; 10 | struct ofp11_port * sw2_port2; 11 | struct ofp11_port * sw3_port1; 12 | struct ofp11_port * sw3_port2; 13 | struct mf_switch* sw1 = mf_switch_create(6); 14 | struct mf_switch* sw2 = mf_switch_create(7); 15 | struct mf_switch* sw3 = mf_switch_create(8); 16 | sw1_port1 = &(sw1->ports[0]); 17 | sw1_port2 = &(sw1->ports[1]); 18 | sw2_port1 = &(sw2->ports[0]); 19 | sw2_port2 = &(sw2->ports[1]); 20 | sw3_port1 = &(sw3->ports[0]); 21 | sw3_port2 = &(sw3->ports[1]); 22 | 23 | struct link_node* src_node1 = link_node_create(sw1, sw1_port1); 24 | struct link_node* dst_node1 = link_node_create(sw2, sw2_port1); 25 | struct link_node* src_node2 = link_node_create(sw1, sw1_port2); 26 | struct link_node* dst_node2 = link_node_create(sw2, sw2_port2); 27 | struct link_node* src_node3 = link_node_create(sw1, sw1_port1); 28 | struct link_node* dst_node3 = link_node_create(sw3, sw3_port1); 29 | /* int i = 0; 30 | for (i = 0; i < 256init cache array size - 6 - 1; i++) 31 | { 32 | link_node_create(sw1, &sw1_port1); 33 | } 34 | */ 35 | link_node_create(sw1, sw1_port1); 36 | link_node_create(sw1, sw1_port1); 37 | struct network_link * network_link1= network_link_create(src_node1, dst_node1); 38 | struct network_link * network_link2 = network_link_create(src_node2, dst_node2); 39 | struct network_link * network_link3 = network_link_create(src_node3, dst_node3); 40 | /* for(i = 0; i < MAX_NETWORK_LINK_NUM; i++) 41 | network_link_create(src_node) 42 | */ 43 | sw_link_insert(&(sw1->link_list),network_link1); 44 | sw_link_insert(&(sw1->link_list),network_link2); 45 | /*struct link_list_element * link1 = link_list_element_create(network_link1); 46 | struct link_list_element * link2 = link_list_element_create(network_link2); 47 | struct link_list_element * link3 = link_list_element_create(network_link3); 48 | struct path_link_list * path_link_list = path_link_list_create(); 49 | struct sw_link_list * sw_link_list = sw_link_list_create(); 50 | network_path_insert(path_link_list, link1); 51 | network_path_insert(path_link_list, link2); 52 | network_path_insert(path_link_list, link3); 53 | path_link_delete(path_link_list, link1); 54 | path_link_delete(path_link_list, link3);*/ 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /tests/wrapper_test.c: -------------------------------------------------------------------------------- 1 | #include "../src/mf_wrapper.h" 2 | #include "../src/mf_utilities.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | int main() 9 | { 10 | time_t timestart, timeend; 11 | // __declspec(align(16)) char * src = "abcd"; 12 | char * src = "abcd"; 13 | char * src1 = "efgh"; 14 | char * src2 = "wxyz"; 15 | char src_block[256]; 16 | // __declspec(align(16)) char dst[5]; 17 | char dst[5]; 18 | dst[4] = '\0'; 19 | char dst1[5]; 20 | dst1[4] = '\0'; 21 | char dst2[5]; 22 | dst2[4] = '\0'; 23 | char dst3[256]; 24 | set_CPU_instruction(); 25 | int i = 0; 26 | time(×tart); 27 | for(; i < 1000000000; i++) 28 | memcpy((char*)dst1, src1, 2); 29 | time(&timeend); 30 | printf("timediff:%f\n", difftime(timeend,timestart)); 31 | /*-----*/ 32 | int j = 0; 33 | time(×tart); 34 | for(j= 0; j < 1000000000; j++) 35 | mf_mov16((uint8_t*)dst, (const uint8_t*)src); 36 | time(&timeend); 37 | printf("timediff:%f\n", difftime(timeend,timestart)); 38 | /*-----*/ 39 | int k = 0; 40 | time(×tart); 41 | for(k= 0; k < 1000000000; k++) 42 | *(uint32_t*)dst2 = *(uint32_t *)src2; 43 | time(&timeend); 44 | printf("timediff:%f\n", difftime(timeend,timestart)); 45 | /*int k = 0; 46 | time(×tart); 47 | for(k= 0; k < 1000000000; k++) 48 | memcpy((uint8_t*)dst3, (uint8_t*)src_block, 256); 49 | time(&timeend); 50 | printf("timediff:%f\n", difftime(timeend,timestart)); 51 | 52 | time(×tart); 53 | for(k= 0; k < 1000000000; k++) 54 | mf_memcpy((uint8_t*)dst3, (uint8_t*)src_block, 256); 55 | time(&timeend); 56 | printf("timediff:%f\n", difftime(timeend,timestart));*/ 57 | printf("dst:%s\n",(char *)dst1); 58 | printf("dst:%s\n",(char *)dst); 59 | printf("dst:%s\n",(char *)dst2); 60 | return 0; 61 | } 62 | 63 | -------------------------------------------------------------------------------- /webui/README.md: -------------------------------------------------------------------------------- 1 | WebUI 2 | ========= 3 | 4 | WebUI designed for Microflow 5 | This work started with the minimalistic Web UI and CLI for VTN Coordinator (Open Daylight Controller) 6 | Read more: Readme.txt 7 | -------------------------------------------------------------------------------- /webui/README.txt: -------------------------------------------------------------------------------- 1 | PLVision 2 | 3 | 4 | 5 | 6 | ----------------------------------------------------------- 7 | ----------------------------------------------------------- 8 | 9 | 10 | Web UI and CLI for VTN Coordinator (Open Daylight Controller) 11 | -------------------------------- 12 | 13 | This is a downloadable package of Web UI and CLI for VTN Coordinator. 14 | 15 | All details and descriptions can be found here: 16 | http://plvision.eu/blog/opendaylight-vtn-coordinator-enabling-webui-and-cli/ 17 | 18 | For more information comtact us: 19 | 20 | 21 | 22 | 23 | ----------------------------------------------------------- 24 | ----------------------------------------------------------- 25 | 26 | 27 | Who we are 28 | ---------------------- 29 | 30 | PLVision is a European software engineering and consulting 31 | company working in the niche of embedded systems, multimedia, 32 | and networking. We help B2B IT companies develop advanced 33 | software solutions, providing a full cycle of software 34 | development and testing in the areas of Networking, Embedded 35 | Systems, Telecom, and Multimedia. 36 | 37 | 38 | We offer 39 | ---------------------- 40 | 41 | * Software Engineering Services 42 | * Manual & Automated Testing 43 | * Support & Maintenance 44 | 45 | 46 | Key technological areas 47 | ---------------------- 48 | 49 | * SDN/OpenDaylight, OpenStack, DPDK 50 | * Routing and Switching 51 | * Embedded Systems 52 | * Embedded Multimedia 53 | 54 | 55 | Contact us 56 | ----------------------- 57 | 58 | For technical questions use: 59 | 60 | 61 | For other inquiries use: 62 | 63 | 64 | http://plvision.eu/ 65 | -------------------------------------------------------------------------------- /webui/icons/Microflow_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PanZhangg/Microflow/644a9dd80b7eb67ed61dd19c7553b14ce60f5e04/webui/icons/Microflow_logo.png -------------------------------------------------------------------------------- /webui/icons/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PanZhangg/Microflow/644a9dd80b7eb67ed61dd19c7553b14ce60f5e04/webui/icons/demo.png -------------------------------------------------------------------------------- /webui/icons/host.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 12 | 31 | 41 | 42 | 43 | 48 | 49 | 50 | SEO 51 | 52 | 54 | 55 | 57 | 58 | 59 | 61 | 62 | 63 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /webui/icons/plvision-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PanZhangg/Microflow/644a9dd80b7eb67ed61dd19c7553b14ce60f5e04/webui/icons/plvision-logo.jpg -------------------------------------------------------------------------------- /webui/icons/router.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PanZhangg/Microflow/644a9dd80b7eb67ed61dd19c7553b14ce60f5e04/webui/icons/router.png -------------------------------------------------------------------------------- /webui/icons/server-fail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PanZhangg/Microflow/644a9dd80b7eb67ed61dd19c7553b14ce60f5e04/webui/icons/server-fail.png -------------------------------------------------------------------------------- /webui/icons/server-ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PanZhangg/Microflow/644a9dd80b7eb67ed61dd19c7553b14ce60f5e04/webui/icons/server-ok.png -------------------------------------------------------------------------------- /webui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 21 | 22 |
23 |
24 |
25 |

Toolbox

26 |
27 | 36 |
37 |
38 | 39 |
40 |
41 |
42 |
43 | 74 |
75 |
76 |
77 |
Microflow WebUI
78 |
79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /webui/odl-rest.js: -------------------------------------------------------------------------------- 1 | 2 | var ODL_ADDR = (getCookie("odl_addr") == null) ? '127.0.0.1' : getCookie("odl_addr"); 3 | var ODL_BASE_URL = "http://" + ODL_ADDR + ":8080/controller/nb/v2/" 4 | var ODL_CNAME = "default/" 5 | var UNAME = 'admin' 6 | var PASSWORD = 'admin' 7 | 8 | var ODL_DEMO = (getCookie("odl_vtn_coordinator_demo") == null) ? true : (getCookie("odl_vtn_coordinator_demo") == "true"); 9 | 10 | var NetNodes = []; 11 | var NetEdges = []; 12 | 13 | var DemoNetNodes = [ 14 | {"id":"00:00:00:00:00:00:00:02"},{"id":"00:00:00:00:00:00:00:03"}, 15 | {"id":"00:00:00:00:00:00:00:01"},{"id":"00:00:00:00:00:00:00:04"}, 16 | {"id":"00:00:00:00:00:00:00:07"},{"id":"00:00:00:00:00:00:00:06"}, 17 | {"id":"00:00:00:00:00:00:00:05"}, 18 | {"id":"10.0.0.6"},{"id":"10.0.0.2"},{"id":"10.0.0.5"}, 19 | {"id":"10.0.0.7"},{"id":"10.0.0.1"},{"id":"10.0.0.4"}, 20 | {"id":"10.0.0.3"},{"id":"10.0.0.8"} 21 | ]; 22 | 23 | var DemoNetEdges = [ 24 | {"source":1,"target":0},{"source":3,"target":0}, 25 | {"source":6,"target":5},{"source":4,"target":6}, 26 | {"source":6,"target":2},{"source":2,"target":0}, 27 | {"source":5,"target":7},{"source":1,"target":8}, 28 | {"source":5,"target":9},{"source":4,"target":10}, 29 | {"source":1,"target":11},{"source":3,"target":12}, 30 | {"source":3,"target":13},{"source":4,"target":14} 31 | ]; 32 | 33 | 34 | if (ODL_DEMO == true) 35 | { 36 | NetNodes = DemoNetNodes; 37 | NetEdges = DemoNetEdges; 38 | document.getElementById('demo').style.display='normal'; 39 | } 40 | else 41 | { 42 | document.getElementById('demo').style.display='none'; 43 | 44 | jQuery(document).ready(function($) { 45 | 46 | var topoRequest = $.ajax({ 47 | type: "GET", 48 | url: ODL_BASE_URL + "topology/" + ODL_CNAME, 49 | dataType: 'json', 50 | username: UNAME, 51 | password: PASSWORD, 52 | xhrFields: { 53 | withCredentials: true 54 | }, 55 | crossDomain: true, 56 | success: function (msg) { 57 | console.log( "Topology response: " + JSON.stringify(msg) ); 58 | 59 | msg['edgeProperties'].forEach(function(entry) { 60 | 61 | var src = entry['edge']['headNodeConnector']['node']['id']; 62 | var dst = entry['edge']['tailNodeConnector']['node']['id']; 63 | 64 | for (var i = 0; i < NetEdges.length; i++) 65 | { 66 | if (NetEdges[i].source == dst && NetEdges[i].target == src) return; 67 | } 68 | 69 | NetEdges.push({"source":src, "target":dst}); 70 | 71 | }); 72 | }, 73 | error: function(jqXHR, textStatus) { 74 | console.error("Topology request failed: " + textStatus ); 75 | } 76 | }); 77 | 78 | var nodeRequest = $.ajax({ 79 | type: "GET", 80 | url: ODL_BASE_URL + "switchmanager/" + ODL_CNAME + "nodes/", 81 | dataType: 'json', 82 | username: UNAME, 83 | password: PASSWORD, 84 | xhrFields: { 85 | withCredentials: true 86 | }, 87 | crossDomain: true, 88 | success: function (msg) { 89 | console.log( "Switch Manager response: " + JSON.stringify(msg) ); 90 | 91 | msg['nodeProperties'].forEach(function(entry) { 92 | NetNodes.push({"id":entry['node']['id']}); 93 | }); 94 | }, 95 | error: function(jqXHR, textStatus) { 96 | console.error("Switch Manager request failed: " + textStatus ); 97 | } 98 | }); 99 | 100 | 101 | 102 | function hostRequest() { 103 | return $.ajax({ 104 | type: "GET", 105 | url: ODL_BASE_URL + "hosttracker/" + ODL_CNAME + "hosts/active", 106 | dataType: 'json', 107 | username: UNAME, 108 | password: PASSWORD, 109 | xhrFields: { 110 | withCredentials: true 111 | }, 112 | crossDomain: true, 113 | success: function (msg) { 114 | console.log( "Host Tracker response: " + JSON.stringify(msg) ); 115 | 116 | msg['hostConfig'].forEach(function(entry) { 117 | NetNodes.push({"id":entry['networkAddress']}); 118 | NetEdges.push({"source":entry['nodeId'], "target":entry['networkAddress']}); 119 | }); 120 | 121 | for (var n = 0; n < NetNodes.length; n++) 122 | { 123 | for (var e = 0; e < NetEdges.length; e++) 124 | { 125 | if (NetEdges[e].source == NetNodes[n].id) NetEdges[e].source = n; 126 | if (NetEdges[e].target == NetNodes[n].id) NetEdges[e].target = n; 127 | } 128 | } 129 | 130 | console.log("Nodes: " + JSON.stringify(NetNodes)); 131 | console.log("Links: " + JSON.stringify(NetEdges)); 132 | 133 | UpdateTopology(); 134 | }, 135 | error: function(jqXHR, textStatus) { 136 | console.error("Host Tracker request failed: " + textStatus ); 137 | } 138 | }); 139 | }; 140 | 141 | $.when(topoRequest, nodeRequest) 142 | .done(function() { 143 | set_serv_state("ODL", true); 144 | hostRequest(); 145 | }); 146 | 147 | }); /* jQuery(document).ready() */ 148 | 149 | } /* ODL_DEMO */ 150 | 151 | 152 | /* 153 | var hdr = { 154 | 'content-type': 'application/json', 155 | 'username': 'admin', 156 | 'password': 'admin', 157 | }; 158 | 159 | function hostRequest() { 160 | return $.ajax({ 161 | type: "GET", 162 | url: "http://172.20.6.159:8080/admin/cluster?x-page-url=devices", 163 | dataType: 'json', 164 | username: UNAME, 165 | password: PASSWORD, 166 | headers: hdr, 167 | xhrFields: { 168 | withCredentials: true 169 | }, 170 | crossDomain: true, 171 | success: function (msg) { 172 | console.warn( "Raw Cluster Info" + msg ); 173 | console.warn( "JSON Cluster Info: " + JSON.stringify(msg) ); 174 | UpdateTopology(); 175 | }, 176 | error: function(jqXHR, textStatus) { 177 | console.error("Host Tracker request failed: " + textStatus ); 178 | } 179 | }); 180 | }; 181 | */ 182 | 183 | function setCookie(name, value, expires, path, domain, secure) { 184 | document.cookie = name + "=" + escape(value) + 185 | ((expires) ? "; expires=" + expires : "") + 186 | ((path) ? "; path=" + path : "") + 187 | ((domain) ? "; domain=" + domain : "") + 188 | ((secure) ? "; secure" : ""); 189 | console.log("READ: " + document.cookie); 190 | } 191 | 192 | function delCookie(name) { 193 | setCookie(name, 0, "Thu, 01 Jan 1970 00:00:01 GMT", "/"); 194 | } 195 | 196 | function getCookie(name) { 197 | var cookie = " " + document.cookie; 198 | var search = " " + name + "="; 199 | var setStr = null; 200 | var offset = 0; 201 | var end = 0; 202 | 203 | if (cookie.length > 0) { 204 | offset = cookie.indexOf(search); 205 | if (offset != -1) { 206 | offset += search.length; 207 | end = cookie.indexOf(";", offset) 208 | if (end == -1) { 209 | end = cookie.length; 210 | } 211 | setStr = unescape(cookie.substring(offset, end)); 212 | } 213 | } 214 | return(setStr); 215 | } 216 | 217 | 218 | -------------------------------------------------------------------------------- /webui/odl-webui.js: -------------------------------------------------------------------------------- 1 | 2 | // Multi-Foci Force Layout: 3 | // http://bl.ocks.org/mbostock/1249681 4 | 5 | // D3.js Drag and Drop, Zoomable, Panning, Collapsible Tree with auto-sizing: 6 | // http://www.robschmuecker.com/d3-js-drag-and-drop-zoomable-panning-collapsible-tree-with-auto-sizing/ 7 | 8 | // Labeled Force Layout: 9 | // http://bl.ocks.org/mbostock/950642 10 | 11 | // Multi-Foci Force Layout: 12 | // http://bl.ocks.org/mbostock/1021953 13 | 14 | var HOST_SIZE = 40; 15 | var HOST_X = -8; 16 | var HOST_Y = -8; 17 | var HOST_IMG = "icons/host.svg"; 18 | 19 | var ROUTER_SIZE = 48; 20 | var ROUTER_X = -8; 21 | var ROUTER_Y = -8; 22 | var ROUTER_IMG = "icons/router.png"; 23 | 24 | var RESIZE_INDEX = 1.08; 25 | 26 | 27 | var width = $("#graph-diagram").width(), 28 | height = $("#graph-diagram").height(); 29 | 30 | function topoResize() { 31 | width = $("#graph-diagram").width(), 32 | height = $("#graph-diagram").height(); 33 | topo = topo.size([width, height]); 34 | svg.attr("width", width).attr("height", height); 35 | topo.resume(); 36 | }; 37 | 38 | d3.select("body") 39 | .on("keydown", function() { 40 | if (d3.event.ctrlKey && (d3.event.keyCode == 49 /* 49dec - 1 */)) 41 | { 42 | d3.event.preventDefault(); 43 | /* Freeze topology */ 44 | svg.selectAll("g.node").classed("fixed", true); 45 | svg.selectAll("g.node") 46 | .each(function(d) { 47 | d.fixed = true; 48 | setCookie("odl:" + d.id + ":x", d.x, "Mon, 01-Jan-2100 00:00:00 GMT", "/"); 49 | setCookie("odl:" + d.id + ":y", d.y, "Mon, 01-Jan-2100 00:00:00 GMT", "/"); 50 | }); 51 | } 52 | else if (d3.event.ctrlKey && (d3.event.keyCode == 50 /* 50dec - 2 */)) 53 | { 54 | d3.event.preventDefault(); 55 | /* Unfreeze topology */ 56 | svg.selectAll("g.node").classed("fixed", false); 57 | svg.selectAll("g.node") 58 | .each(function(d) { 59 | if (d.fixed == true) { 60 | d.fixed = false; 61 | delCookie("odl:" + d.id + ":x"); 62 | delCookie("odl:" + d.id + ":y"); 63 | } 64 | }); 65 | 66 | topo.resume(); 67 | } 68 | }); 69 | 70 | 71 | var svg = d3.select("#graph-diagram").append("svg:svg") 72 | .attr("id", "topo_svg") 73 | .attr("width", width) 74 | .attr("height", height); 75 | 76 | var link = svg.selectAll(".link"), 77 | node = svg.selectAll(".node"); 78 | 79 | var topo = d3.layout.force() 80 | .size([width, height]) 81 | .charge(-400) 82 | .linkDistance(100) 83 | .gravity(0.1) 84 | .on("tick", tick); 85 | 86 | function tick() { 87 | link.attr("x1", function(d) { return d.source.x; }) 88 | .attr("y1", function(d) { return d.source.y; }) 89 | .attr("x2", function(d) { return d.target.x; }) 90 | .attr("y2", function(d) { return d.target.y; }); 91 | 92 | node.attr("transform", function(d) { 93 | return "translate(" + (d.x - 18) + "," + (d.y - 18) + ")"; 94 | }); 95 | } 96 | 97 | var drag = topo.drag().on("dragend", dragend); 98 | 99 | 100 | function UpdateTopology() { 101 | //d3.json("graph.json", function(error, graph) { 102 | 103 | NetNodes.forEach(function(d, i) { 104 | if (getCookie("odl:" + d.id + ":x") != null) { 105 | d.fixed = true; 106 | d.x = parseFloat(getCookie("odl:" + d.id + ":x")); 107 | d.y = parseFloat(getCookie("odl:" + d.id + ":y")); 108 | } 109 | }); 110 | 111 | topo.nodes(NetNodes) 112 | .links(NetEdges) 113 | .start(); 114 | 115 | link = link.data(NetEdges) 116 | .enter().append("line") 117 | .attr("class", "link"); 118 | 119 | node = node.data(NetNodes) 120 | .enter().append("g") 121 | .attr("class", function(d) { return (getCookie("odl:" + d.id + ":x") == null) ? "node" : "node fixed"; }) 122 | .on("dblclick", dblclick) 123 | .on("mouseover", mouseover) 124 | .on("mouseout", mouseout) 125 | .call(drag); 126 | 127 | node.append("image") 128 | .attr("xlink:href", function(d) { return (d.id.indexOf(":") == -1) ? HOST_IMG : ROUTER_IMG;}) 129 | .attr("x", ROUTER_X) 130 | .attr("y", ROUTER_Y) 131 | .attr("width", function(d) { return (d.id.indexOf(":") == -1) ? HOST_SIZE : ROUTER_SIZE;}) 132 | .attr("height", function(d) { return (d.id.indexOf(":") == -1) ? HOST_SIZE : ROUTER_SIZE;}); 133 | 134 | node.append("text") 135 | .attr("dx", function(d) { return (d.id.indexOf(":") == -1) ? -10 : -40;}) 136 | .attr("dy", "3.2em") 137 | .text(function(d) { return d.id; }); 138 | } 139 | //); 140 | 141 | if (ODL_DEMO == true) { 142 | UpdateTopology(); 143 | } 144 | 145 | function dblclick(d) { 146 | d3.select(this).classed("fixed", d.fixed = false); 147 | delCookie("odl:" + d.id + ":x"); 148 | delCookie("odl:" + d.id + ":y"); 149 | topo.resume(); 150 | } 151 | 152 | function mouseover(d) { 153 | 154 | if (d.id.indexOf(":") == -1) 155 | { 156 | var hostWidth = HOST_SIZE * RESIZE_INDEX; 157 | var hostX = HOST_X - (hostWidth - HOST_SIZE) / 2; 158 | 159 | node.each(function(d) { 160 | if (d.id.indexOf(":") == -1) { 161 | d3.select(this).select("image").attr("width", hostWidth).attr("x", hostX); 162 | } 163 | }); 164 | } 165 | else 166 | { 167 | var routerWidth = ROUTER_SIZE * RESIZE_INDEX; 168 | var routerX = ROUTER_X - (routerWidth - ROUTER_SIZE) / 2; 169 | 170 | node.each(function(d) { 171 | if (d.id.indexOf(":") != -1) { 172 | d3.select(this).select("image").attr("width", routerWidth).attr("x", routerX); 173 | } 174 | }); 175 | } 176 | } 177 | 178 | function mouseout(d) { 179 | node.select("image") 180 | .attr('width', function(d) { return (d.id.indexOf(":") == -1) ? HOST_SIZE : ROUTER_SIZE; }).attr('x', ROUTER_X); 181 | } 182 | 183 | function dragend(d) { 184 | d3.select(this).classed("fixed", d.fixed = d3.event.sourceEvent.ctrlKey || d.fixed); 185 | 186 | if (d.fixed) { 187 | setCookie("odl:" + d.id + ":x", d.x, "Mon, 01-Jan-2100 00:00:00 GMT", "/"); 188 | setCookie("odl:" + d.id + ":y", d.y, "Mon, 01-Jan-2100 00:00:00 GMT", "/"); 189 | } 190 | } 191 | 192 | 193 | /* EOF */ 194 | -------------------------------------------------------------------------------- /webui/styles.css: -------------------------------------------------------------------------------- 1 | 2 | * { 3 | margin: 0; 4 | padding: 0; 5 | } 6 | 7 | html { 8 | width: calc(100% - 0px); 9 | height: calc(100% - 0px); 10 | } 11 | 12 | body { 13 | overflow:hidden; 14 | width: calc(100% - 32px); 15 | height: calc(100% - 32px); 16 | margin: 16px; 17 | } 18 | 19 | line.link { 20 | stroke: #999; 21 | stroke-opacity: .6; 22 | } 23 | 24 | .node text { 25 | pointer-events: none; 26 | font: 12px sans-serif; 27 | } 28 | 29 | .node.fixed text { 30 | pointer-events: none; 31 | font: 12px sans-serif; 32 | font-weight: bold; 33 | } 34 | 35 | .outline { 36 | border: 4px solid #4682B4; 37 | border-style: ridge; 38 | width: calc(100% - 20px - 4px * 2); 39 | height: calc(100% - 20px - 4px * 2); 40 | } 41 | 42 | .demo { 43 | position: absolute; 44 | left:0; 45 | right:0; 46 | margin-left:auto; 47 | margin-right:auto; 48 | height: calc(65%); 49 | z-index: -1; 50 | } 51 | 52 | .logo { 53 | position: absolute; 54 | left: 30px; 55 | top: 20px; 56 | z-index: -1; 57 | } 58 | 59 | .graph { 60 | position: relative; 61 | } 62 | 63 | .controller { 64 | position: absolute; 65 | left: 30px; 66 | bottom: 30px; 67 | z-index: -1; 68 | } 69 | 70 | .layer1 { 71 | position: relative; 72 | } 73 | 74 | .layer2 { 75 | position: absolute; 76 | top: 20px; 77 | } 78 | --------------------------------------------------------------------------------