├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── Datagen ├── .gitignore ├── Cargo.toml └── src │ ├── bin │ └── checksum.rs │ ├── lib.rs │ └── main.rs ├── Example ├── CMakeLists.txt ├── broadcaster.cpp ├── capture.cpp └── shell.cpp ├── HAL ├── CMakeLists.txt ├── include │ ├── router_hal.h │ └── router_hal_common.h └── src │ ├── linux │ ├── platform │ │ ├── standard.h │ │ └── testing.h │ └── router_hal.cpp │ ├── macOS │ └── router_hal.cpp │ ├── stdio │ └── router_hal.cpp │ └── xilinx │ └── router_hal.c ├── Homework ├── boilerplate │ ├── .gitignore │ ├── Makefile │ ├── checksum.cpp │ ├── forwarding.cpp │ ├── lookup.cpp │ ├── main.cpp │ ├── protocol.cpp │ ├── rip.h │ └── router.h ├── checksum │ ├── .gitignore │ ├── Makefile │ ├── checksum.cpp │ ├── data │ │ ├── checksum_input1.pcap │ │ ├── checksum_input2.pcap │ │ ├── checksum_input3.pcap │ │ ├── checksum_input4.pcap │ │ ├── checksum_output1.out │ │ ├── checksum_output2.out │ │ ├── checksum_output3.out │ │ └── checksum_output4.out │ ├── grade.py │ └── main.cpp ├── forwarding │ ├── .gitignore │ ├── Makefile │ ├── data │ │ ├── forwarding_input1.pcap │ │ ├── forwarding_input2.pcap │ │ ├── forwarding_input3.pcap │ │ ├── forwarding_input4.pcap │ │ ├── forwarding_output1.out │ │ ├── forwarding_output2.out │ │ ├── forwarding_output3.out │ │ └── forwarding_output4.out │ ├── forwarding.cpp │ ├── grade.py │ └── main.cpp ├── lookup │ ├── .gitignore │ ├── Makefile │ ├── data │ │ ├── lookup_input1.in │ │ ├── lookup_input2.in │ │ ├── lookup_input3.in │ │ ├── lookup_input4.in │ │ ├── lookup_output1.out │ │ ├── lookup_output2.out │ │ ├── lookup_output3.out │ │ └── lookup_output4.out │ ├── grade.py │ ├── lookup.cpp │ ├── main.cpp │ └── router.h ├── protocol │ ├── .gitignore │ ├── Makefile │ ├── data │ │ ├── protocol_input1.pcap │ │ ├── protocol_input10.pcap │ │ ├── protocol_input11.pcap │ │ ├── protocol_input12.pcap │ │ ├── protocol_input2.pcap │ │ ├── protocol_input3.pcap │ │ ├── protocol_input4.pcap │ │ ├── protocol_input5.pcap │ │ ├── protocol_input6.pcap │ │ ├── protocol_input7.pcap │ │ ├── protocol_input8.pcap │ │ ├── protocol_input9.pcap │ │ ├── protocol_output1.out │ │ ├── protocol_output10.out │ │ ├── protocol_output11.out │ │ ├── protocol_output12.out │ │ ├── protocol_output2.out │ │ ├── protocol_output3.out │ │ ├── protocol_output4.out │ │ ├── protocol_output5.out │ │ ├── protocol_output6.out │ │ ├── protocol_output7.out │ │ ├── protocol_output8.out │ │ └── protocol_output9.out │ ├── grade.py │ ├── main.cpp │ ├── protocol.cpp │ └── rip.h └── router │ ├── Makefile │ ├── addr2u32.py │ └── main.cpp ├── readme.md └── report.pdf /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .vscode/ 3 | .idea/ 4 | cmake-build-*/ 5 | 6 | # Created by https://www.gitignore.io/api/c++,cmake 7 | # Edit at https://www.gitignore.io/?templates=c++,cmake 8 | 9 | ### C++ ### 10 | # Prerequisites 11 | *.d 12 | 13 | # Compiled Object files 14 | *.slo 15 | *.lo 16 | *.o 17 | *.obj 18 | 19 | # Precompiled Headers 20 | *.gch 21 | *.pch 22 | 23 | # Compiled Dynamic libraries 24 | *.so 25 | *.dylib 26 | *.dll 27 | 28 | # Fortran module files 29 | *.mod 30 | *.smod 31 | 32 | # Compiled Static libraries 33 | *.lai 34 | *.la 35 | *.a 36 | *.lib 37 | 38 | # Executables 39 | *.exe 40 | *.out 41 | *.app 42 | 43 | ### CMake ### 44 | CMakeLists.txt.user 45 | CMakeCache.txt 46 | CMakeFiles 47 | CMakeScripts 48 | Testing 49 | Makefile 50 | cmake_install.cmake 51 | install_manifest.txt 52 | compile_commands.json 53 | CTestTestfile.cmake 54 | _deps 55 | 56 | ### CMake Patch ### 57 | # External projects 58 | *-prefix/ 59 | 60 | # End of https://www.gitignore.io/api/c++,cmake 61 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MashPlant/Router-Lab/d98900c038bc9b892acb430da125f460d8857760/.gitmodules -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | project(ROUTER_LAB LANGUAGES C CXX) 3 | 4 | set(CMAKE_C_STANDARD 11) 5 | set(CMAKE_CXX_STANDARD 11) 6 | 7 | set(BACKEND LINUX CACHE STRING "Router platform") 8 | set(BACKEND_VALUES "Linux" "Xilinx" "macOS" "stdio") 9 | set_property(CACHE BACKEND PROPERTY STRINGS ${BACKEND_VALUES}) 10 | list(FIND BACKEND_VALUES ${BACKEND} BACKEND_INDEX) 11 | 12 | if(${BACKEND_INDEX} EQUAL -1) 13 | message(WARNING "Backend ${BACKEND} not supported, valid items are: ${BACKEND_VALUES}") 14 | set(BACKEND "Linux") 15 | endif() 16 | 17 | string(TOUPPER "${BACKEND}" BACKEND) 18 | add_definitions("-DROUTER_BACKEND_${BACKEND}") 19 | 20 | add_subdirectory(HAL) 21 | add_subdirectory(Example) 22 | -------------------------------------------------------------------------------- /Datagen/.gitignore: -------------------------------------------------------------------------------- 1 | *.pcap 2 | *.out 3 | 4 | # Created by https://www.gitignore.io/api/rust,vim 5 | # Edit at https://www.gitignore.io/?templates=rust,vim 6 | 7 | ### Rust ### 8 | # Generated by Cargo 9 | # will have compiled files and executables 10 | /target/ 11 | 12 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 13 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 14 | Cargo.lock 15 | 16 | # These are backup files generated by rustfmt 17 | **/*.rs.bk 18 | 19 | ### Vim ### 20 | # Swap 21 | [._]*.s[a-v][a-z] 22 | [._]*.sw[a-p] 23 | [._]s[a-rt-v][a-z] 24 | [._]ss[a-gi-z] 25 | [._]sw[a-p] 26 | 27 | # Session 28 | Session.vim 29 | Sessionx.vim 30 | 31 | # Temporary 32 | .netrwhist 33 | *~ 34 | # Auto-generated tag files 35 | tags 36 | # Persistent undo 37 | [._]*.un~ 38 | 39 | # End of https://www.gitignore.io/api/rust,vim 40 | -------------------------------------------------------------------------------- /Datagen/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "datagen" 3 | version = "0.1.0" 4 | authors = ["Jiajie Chen "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | pcap-file = "0.10" 11 | rand = "0.6" 12 | structopt = "0.2" -------------------------------------------------------------------------------- /Datagen/src/bin/checksum.rs: -------------------------------------------------------------------------------- 1 | extern crate datagen; 2 | extern crate pcap_file; 3 | extern crate rand; 4 | extern crate structopt; 5 | 6 | use pcap_file::*; 7 | use rand::Rng; 8 | use std::fs::File; 9 | use std::io::BufWriter; 10 | use std::io::Write; 11 | use structopt::StructOpt; 12 | 13 | #[derive(StructOpt, Debug)] 14 | struct Opt { 15 | /// file names are {input,output}${index}.pcap 16 | #[structopt(name = "index")] 17 | index: String, 18 | 19 | /// number of packets for each type 20 | #[structopt(name = "packets")] 21 | packets: usize, 22 | 23 | /// allow generation of bad IP packets 24 | #[structopt(long = "ip")] 25 | ip: bool, 26 | 27 | /// append more bytes 28 | #[structopt(long = "large")] 29 | large: bool, 30 | } 31 | 32 | fn main() { 33 | let opt = Opt::from_args(); 34 | println!("options: {:?}", opt); 35 | let mut rng = rand::thread_rng(); 36 | let file = File::create(format!("checksum_input{}.pcap", opt.index)).unwrap(); 37 | let ans_file = File::create(format!("checksum_output{}.out", opt.index)).unwrap(); 38 | let mut header = PcapHeader::with_datalink(DataLink::ETHERNET); 39 | header.snaplen = 0x40000; 40 | let mut writer = PcapWriter::with_header(header, file).unwrap(); 41 | let mut ans_writer = BufWriter::new(ans_file); 42 | 43 | for i in 0..opt.packets { 44 | let sec = i as u32; 45 | let types = if opt.ip { 2 } else { 1 }; 46 | let file_size = if opt.large { 1000 } else { 10 }; 47 | let packet_type = rng.gen_range(0, types); 48 | let frame = match packet_type { 49 | 0 => { 50 | // good IP 51 | let mut data = datagen::parse_string("01005e000001c0562718cc8e81000001080046c00020000040000102041700000000e0000001940400001164ee9b00000000"); 52 | let extra_length = rng.gen_range(0, file_size); 53 | for _ in 0..extra_length { 54 | data.push(rng.gen()); 55 | } 56 | data = datagen::update_ip_checksum(data); 57 | write!(ans_writer, "Yes\n").expect("write"); 58 | data 59 | } 60 | 1 => { 61 | // bad IP 62 | let mut data = datagen::parse_string("74EAC8233333 001217122345 8100 0001 080045000020000040004011DD63B7AD71B701020304E36E2766000C635A3132330A"); 63 | let extra_length = rng.gen_range(0, file_size); 64 | for _ in 0..extra_length { 65 | data.push(rng.gen()); 66 | } 67 | data = datagen::update_ip_checksum(data); 68 | data[28] ^= rng.gen_range(1, 255); 69 | data[29] ^= rng.gen_range(1, 255); 70 | write!(ans_writer, "No\n").expect("write"); 71 | data 72 | } 73 | _ => unimplemented!(), 74 | }; 75 | writer 76 | .write_packet(&Packet::new_owned(sec, 0, frame.len() as u32, frame)) 77 | .unwrap(); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Datagen/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub fn parse_string(input: &str) -> Vec { 2 | let mut cur = 0; 3 | let mut index = 0; 4 | let mut result = Vec::new(); 5 | for ch in input.bytes() { 6 | let num = if ch >= b'0' && ch <= b'9' { 7 | ch - b'0' 8 | } else if ch >= b'a' && ch <= b'f' { 9 | ch - b'a' + 10 10 | } else if ch >= b'A' && ch <= b'F' { 11 | ch - b'A' + 10 12 | } else { 13 | continue; 14 | }; 15 | 16 | if index == 0 { 17 | index = 1; 18 | cur = num << 4; 19 | } else { 20 | result.push(cur | num); 21 | index = 0; 22 | } 23 | } 24 | result 25 | } 26 | 27 | pub fn update_ip_checksum(mut data: Vec) -> Vec { 28 | // calculate ip checksum 29 | assert_eq!(data[16], 0x08); 30 | assert_eq!(data[17], 0x00); 31 | //assert_eq!(data[18], 0x45); 32 | data[28] = 0; 33 | data[29] = 0; 34 | let mut checksum = 0; 35 | let mut len = ((data[18] & 0xF) * 2) as usize; 36 | for i in 0..len { 37 | checksum += ((data[18 + i * 2] as u32) << 8) | (data[18 + i * 2 + 1] as u32); 38 | } 39 | while checksum >= 0x10000 { 40 | checksum -= 0x10000; 41 | checksum += 1; 42 | } 43 | data[28] = !((checksum >> 8) as u8); 44 | data[29] = !(checksum as u8); 45 | 46 | data 47 | } 48 | -------------------------------------------------------------------------------- /Datagen/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | -------------------------------------------------------------------------------- /Example/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | add_executable(shell shell.cpp) 4 | target_include_directories(shell PRIVATE ../HAL/include) 5 | target_link_libraries(shell router_hal readline ncurses) 6 | 7 | add_executable(broadcaster broadcaster.cpp) 8 | target_include_directories(broadcaster PRIVATE ../HAL/include) 9 | target_link_libraries(broadcaster router_hal) 10 | 11 | add_executable(capture capture.cpp) 12 | target_include_directories(capture PRIVATE ../HAL/include) 13 | target_link_libraries(capture router_hal) -------------------------------------------------------------------------------- /Example/broadcaster.cpp: -------------------------------------------------------------------------------- 1 | #include "router_hal.h" 2 | #include 3 | #include 4 | #include 5 | 6 | void printMAC(macaddr_t mac) { 7 | printf("%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], 8 | mac[4], mac[5]); 9 | } 10 | 11 | uint8_t packet[2048]; 12 | bool cont = false; 13 | 14 | // 10.0.0.1 ~ 10.0.3.1 15 | in_addr_t addrs[N_IFACE_ON_BOARD] = {0x0100000a, 0x0101000a, 0x0102000a, 16 | 0x0103000a}; 17 | 18 | void interrupt(int _) { 19 | printf("Interrupt\n"); 20 | cont = false; 21 | return; 22 | } 23 | 24 | int main() { 25 | fprintf(stderr, "HAL init: %d\n", HAL_Init(1, addrs)); 26 | for (int i = 0; i < N_IFACE_ON_BOARD; i++) { 27 | macaddr_t mac; 28 | HAL_GetInterfaceMacAddress(i, mac); 29 | fprintf(stderr, "%d: %02X:%02X:%02X:%02X:%02X:%02X\n", i, mac[0], mac[1], 30 | mac[2], mac[3], mac[4], mac[5]); 31 | } 32 | 33 | while (1) { 34 | int mask = (1 << N_IFACE_ON_BOARD) - 1; 35 | macaddr_t src_mac; 36 | macaddr_t dst_mac; 37 | int if_index; 38 | int res = HAL_ReceiveIPPacket(mask, packet, sizeof(packet), src_mac, 39 | dst_mac, 1000, &if_index); 40 | if (res > 0) { 41 | for (int i = 0; i < N_IFACE_ON_BOARD;i++) { 42 | HAL_SendIPPacket(i, packet, res, src_mac); 43 | } 44 | } else if (res == 0) { 45 | fprintf(stderr, "Timeout\n"); 46 | } else { 47 | fprintf(stderr, "Error: %d\n", res); 48 | break; 49 | } 50 | } 51 | return 0; 52 | } -------------------------------------------------------------------------------- /Example/capture.cpp: -------------------------------------------------------------------------------- 1 | #include "router_hal.h" 2 | #include 3 | #include 4 | #include 5 | 6 | void printMAC(macaddr_t mac) { 7 | printf("%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], 8 | mac[4], mac[5]); 9 | } 10 | 11 | uint8_t packet[2048]; 12 | bool cont = false; 13 | 14 | // 10.0.0.1 ~ 10.0.3.1 15 | in_addr_t addrs[N_IFACE_ON_BOARD] = {0x0100000a, 0x0101000a, 0x0102000a, 16 | 0x0103000a}; 17 | 18 | int main() { 19 | fprintf(stderr, "HAL init: %d\n", HAL_Init(1, addrs)); 20 | for (int i = 0; i < N_IFACE_ON_BOARD; i++) { 21 | macaddr_t mac; 22 | HAL_GetInterfaceMacAddress(i, mac); 23 | fprintf(stderr, "%d: %02X:%02X:%02X:%02X:%02X:%02X\n", i, mac[0], mac[1], 24 | mac[2], mac[3], mac[4], mac[5]); 25 | } 26 | 27 | while (1) { 28 | int mask = (1 << N_IFACE_ON_BOARD) - 1; 29 | macaddr_t src_mac; 30 | macaddr_t dst_mac; 31 | int if_index; 32 | int res = HAL_ReceiveIPPacket(mask, packet, sizeof(packet), src_mac, 33 | dst_mac, 1000, &if_index); 34 | if (res > 0) { 35 | printf("Got IP packet of length %d from port %d\n", res, if_index); 36 | printf("Src MAC: "); 37 | printMAC(src_mac); 38 | printf(" Dst MAC: "); 39 | printMAC(dst_mac); 40 | printf("\nData: "); 41 | for (int i = 0; i < res; i++) { 42 | printf("%02X ", packet[i]); 43 | } 44 | printf("\n"); 45 | } else if (res == 0) { 46 | fprintf(stderr, "Timeout\n"); 47 | } else { 48 | fprintf(stderr, "Error: %d\n", res); 49 | break; 50 | } 51 | } 52 | return 0; 53 | } -------------------------------------------------------------------------------- /Example/shell.cpp: -------------------------------------------------------------------------------- 1 | #include "router_hal.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | void printMAC(macaddr_t mac) { 11 | printf("%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], 12 | mac[4], mac[5]); 13 | } 14 | 15 | // char buffer[2048]; 16 | char *buffer; 17 | uint8_t packet[2048]; 18 | bool cont = false; 19 | 20 | // 10.0.0.1 ~ 10.0.3.1 21 | in_addr_t addrs[N_IFACE_ON_BOARD] = {0x0100000a, 0x0101000a, 0x0102000a, 22 | 0x0103000a}; 23 | 24 | void interrupt(int _) { 25 | printf("Interrupt\n"); 26 | cont = false; 27 | return; 28 | } 29 | 30 | int main() { 31 | printf("HAL init: %d\n", HAL_Init(1, addrs)); 32 | for (int i = 0; i < N_IFACE_ON_BOARD;i++) { 33 | macaddr_t mac; 34 | HAL_GetInterfaceMacAddress(i, mac); 35 | printf("%d: %02X:%02X:%02X:%02X:%02X:%02X\n", i, mac[0], mac[1], mac[2], 36 | mac[3], mac[4], mac[5]); 37 | } 38 | signal(SIGINT, interrupt); 39 | rl_bind_key('\t', rl_insert); 40 | while ((buffer = readline("> "))) { 41 | add_history(buffer); 42 | if (strcmp(buffer, "time") == 0) { 43 | printf("Current tick %lld\n", HAL_GetTicks()); 44 | } else if (strncmp(buffer, "arp", strlen("arp")) == 0) { 45 | int if_index; 46 | int ip1, ip2, ip3, ip4; 47 | sscanf(buffer, "arp %d %d.%d.%d.%d", &if_index, &ip1, &ip2, &ip3, &ip4); 48 | printf("Get arp address of %d.%d.%d.%d if %d\n", ip1, ip2, ip3, ip4, 49 | if_index); 50 | in_addr_t ip = (ip4 << 24) | (ip3 << 16) | (ip2 << 8) | ip1; 51 | macaddr_t mac; 52 | int res = HAL_ArpGetMacAddress(if_index, ip, mac); 53 | if (res == 0) { 54 | printf("Found: "); 55 | printMAC(mac); 56 | printf("\n"); 57 | } else { 58 | printf("Not found: %d\n", res); 59 | } 60 | } else if (strncmp(buffer, "mac", strlen("mac")) == 0) { 61 | int if_index; 62 | sscanf(buffer, "mac %d", &if_index); 63 | macaddr_t mac; 64 | int res = HAL_GetInterfaceMacAddress(if_index, mac); 65 | if (res == 0) { 66 | printf("Found: "); 67 | printMAC(mac); 68 | printf("\n"); 69 | } else { 70 | printf("Not found: %d\n", res); 71 | } 72 | } else if (strncmp(buffer, "cap", strlen("cap")) == 0) { 73 | int mask = (1 << N_IFACE_ON_BOARD) - 1; 74 | macaddr_t src_mac; 75 | macaddr_t dst_mac; 76 | int if_index; 77 | int res = HAL_ReceiveIPPacket(mask, packet, sizeof(packet), src_mac, 78 | dst_mac, 1000, &if_index); 79 | if (res > 0) { 80 | printf("Got IP packet of length %d from port %d\n", res, if_index); 81 | printf("Src MAC: "); 82 | printMAC(src_mac); 83 | printf(" Dst MAC: "); 84 | printMAC(dst_mac); 85 | printf("\nData: "); 86 | for (int i = 0; i < res; i++) { 87 | printf("%02X ", packet[i]); 88 | } 89 | printf("\n"); 90 | } else if (res == 0) { 91 | printf("Timeout\n"); 92 | } else { 93 | printf("Error: %d\n", res); 94 | } 95 | } else if (strncmp(buffer, "out", strlen("out")) == 0) { 96 | int if_index; 97 | sscanf(buffer, "out %d", &if_index); 98 | macaddr_t dst_mac; 99 | int len = 64; 100 | for (int i = 0; i < len; i++) { 101 | packet[i] = rand(); 102 | } 103 | for (int i = 0; i < sizeof(macaddr_t);i++) { 104 | dst_mac[i] = rand(); 105 | } 106 | int res = HAL_SendIPPacket(if_index, packet, len, dst_mac); 107 | if (res == 0) { 108 | printf("Packet sent\n"); 109 | } else { 110 | printf("Sent failed: %d\n", res); 111 | } 112 | } else if (strncmp(buffer, "loop", strlen("loop")) == 0) { 113 | cont = true; 114 | while (getch() == ERR && cont) { 115 | int mask = (1 << N_IFACE_ON_BOARD) - 1; 116 | macaddr_t src_mac; 117 | macaddr_t dst_mac; 118 | int if_index; 119 | int res = HAL_ReceiveIPPacket(mask, packet, sizeof(packet), src_mac, 120 | dst_mac, 1000, &if_index); 121 | if (res < 0) { 122 | printf("loop failed with %d\n", res); 123 | break; 124 | } 125 | } 126 | } else if (strncmp(buffer, "quit", strlen("quit")) == 0) { 127 | free(buffer); 128 | break; 129 | } else { 130 | printf("Unknown command.\n"); 131 | printf("Usage:\n"); 132 | printf("\ttime: show current ticks\n"); 133 | printf("\tarp index a.b.c.d: lookup arp\n"); 134 | printf("\tmac index: print MAC address of interface\n"); 135 | printf("\tcap: capture one packet\n"); 136 | printf("\tout index: send random packet to interface\n"); 137 | printf("\tloop: read packets until interrupted\n"); 138 | printf("\tquit: exit shell\n"); 139 | } 140 | free(buffer); 141 | } 142 | return 0; 143 | } 144 | -------------------------------------------------------------------------------- /HAL/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if(${BACKEND} STREQUAL LINUX) 2 | file(GLOB_RECURSE SOURCES src/linux/*.cpp) 3 | file(GLOB_RECURSE HEADERS src/linux/*.h) 4 | set(LIBRARIES pcap) 5 | elseif(${BACKEND} STREQUAL MACOS) 6 | file(GLOB_RECURSE SOURCES src/macOS/*.cpp) 7 | set(LIBRARIES pcap) 8 | elseif(${BACKEND} STREQUAL STDIO) 9 | file(GLOB_RECURSE SOURCES src/stdio/*.cpp) 10 | set(LIBRARIES pcap) 11 | elseif(${BACKEND} STREQUAL XILINX) 12 | file(GLOB_RECURSE SOURCES src/xilinx/*.c) 13 | endif() 14 | 15 | add_library(router_hal ${SOURCES} ${HEADERS}) 16 | target_include_directories(router_hal PUBLIC include) 17 | target_link_libraries(router_hal ${LIBRARIES}) 18 | 19 | option(HAL_TESTING "Use testing parameters for HAL" OFF) 20 | if(${HAL_TESTING} STREQUAL ON) 21 | add_definitions("-DHAL_PLATFORM_TESTING") 22 | endif() -------------------------------------------------------------------------------- /HAL/include/router_hal.h: -------------------------------------------------------------------------------- 1 | #ifndef __ROUTER_HAL_H__ 2 | #define __ROUTER_HAL_H__ 3 | 4 | #include 5 | #include 6 | #ifdef ROUTER_BACKEND_LINUX 7 | #include 8 | #elif defined ROUTER_BACKEND_MACOS 9 | #include 10 | #elif defined ROUTER_BACKEND_STDIO 11 | #include 12 | #elif defined ROUTER_BACKEND_XILINX 13 | typedef uint32_t in_addr_t; 14 | #endif 15 | // in_addr_t 是以大端序存储的,意味着 1.2.3.4 对应 0x04030201 16 | 17 | #define N_IFACE_ON_BOARD 4 18 | typedef uint8_t macaddr_t[6]; 19 | 20 | enum HAL_ERROR_NUMBER { 21 | HAL_ERR_INVALID_PARAMETER = -1000, 22 | HAL_ERR_IP_NOT_EXIST, 23 | HAL_ERR_IFACE_NOT_EXIST, 24 | HAL_ERR_CALLED_BEFORE_INIT, 25 | HAL_ERR_EOF, 26 | HAL_ERR_NOT_SUPPORTED, 27 | HAL_ERR_UNKNOWN, 28 | }; 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif 33 | 34 | /** 35 | * @brief 初始化,在所有其他函数调用前调用且仅调用一次 36 | * 37 | * @param debug IN,零表示关闭调试信息,非零表示输出调试信息到标准错误输出 38 | * @param if_addrs IN,包含 N_IFACE_ON_BOARD 个 IPv4 地址,对应每个端口的 IPv4 39 | * 地址 40 | * 41 | * @return int 0 表示成功,非 0 表示失败 42 | */ 43 | int HAL_Init(int debug, in_addr_t if_addrs[N_IFACE_ON_BOARD]); 44 | 45 | /** 46 | * @brief 获取从启动到当前时刻的毫秒数 47 | * 48 | * @return uint64_t 毫秒数 49 | */ 50 | uint64_t HAL_GetTicks(); 51 | 52 | /** 53 | * @brief 从 ARP 表中查询 IPv4 对应的 MAC 地址 54 | * 55 | * 如果是表中不存在的IP,系统将自动发送 ARP 56 | * 报文进行查询,待对方主机回应后可重新调用本接口从表中查询 部分后端会限制发送的 57 | * ARP 报文数量,如每秒向同一个主机最多发送一个 ARP 报文 58 | * 59 | * @param if_index IN,接口索引号,[0, N_IFACE_ON_BOARD-1] 60 | * @param ip IN,要查询的 IP 地址 61 | * @param o_mac OUT,查询结果 MAC 地址 62 | * @return int 0 表示成功,非 0 为失败 63 | */ 64 | int HAL_ArpGetMacAddress(int if_index, in_addr_t ip, macaddr_t o_mac); 65 | 66 | /** 67 | * @brief 获取网卡的 MAC 地址,如果为全 0 代表系统中不存在该网卡或者获取失败 68 | * 69 | * @param if_index IN,接口索引号,[0, N_IFACE_ON_BOARD-1] 70 | * @param o_mac OUT,网卡的 MAC 地址 71 | * @return int 0 表示成功,非 0 为失败 72 | */ 73 | int HAL_GetInterfaceMacAddress(int if_index, macaddr_t o_mac); 74 | 75 | /** 76 | * @brief 接收一个 IPv4 77 | * 报文,保证不会收到自己发送的报文;请保证缓冲区大小足够大(如大于常见的 78 | * MTU),报文只能读取一次 79 | * 80 | * @param if_index_mask IN,接口索引号的 bitset,最低的 N_IFACE_ON_BOARD 81 | * 位有效,对于每一位,1 代表接收对应接口,0 82 | * 代表不接收;部分平台仅支持所有接口都开启接收的情况 83 | * @param buffer IN,接收缓冲区,由调用者分配 84 | * @param length IN,接收缓存区大小 85 | * @param src_mac OUT,IPv4 报文下层的源 MAC 地址 86 | * @param dst_mac OUT,IPv4 报文下层的目的 MAC 地址 87 | * @param timeout IN,设置接收超时时间(毫秒),-1 表示无限等待 88 | * @param if_index OUT,实际接收到的报文来源的接口号,不能为空指针 89 | * @return int >0 表示实际接收的报文长度,=0 表示超时返回,<0 表示发生错误 90 | */ 91 | int HAL_ReceiveIPPacket(int if_index_mask, uint8_t *buffer, size_t length, 92 | macaddr_t src_mac, macaddr_t dst_mac, int64_t timeout, 93 | int *if_index); 94 | 95 | /** 96 | * @brief 发送一个 IP 报文,它的源 MAC 地址就是对应接口的 MAC 地址 97 | * 98 | * @param if_index IN,接口索引号,[0, N_IFACE_ON_BOARD-1] 99 | * @param buffer IN,发送缓冲区 100 | * @param length IN,待发送报文的长度 101 | * @param dst_mac IN,IPv4 报文下层的目的 MAC 地址 102 | * @return int 0 表示成功,非 0 为失败 103 | */ 104 | int HAL_SendIPPacket(int if_index, uint8_t *buffer, size_t length, 105 | macaddr_t dst_mac); 106 | 107 | #ifdef __cplusplus 108 | } 109 | #endif 110 | 111 | #endif -------------------------------------------------------------------------------- /HAL/include/router_hal_common.h: -------------------------------------------------------------------------------- 1 | #ifndef __ROUTER_HAL_COMMON_H__ 2 | #define __ROUTER_HAL_COMMON_H__ 3 | 4 | // don't include this file in your own code. 5 | #include "router_hal.h" 6 | #include 7 | 8 | // send igmp join to the multicast address 9 | void HAL_JoinIGMPGroup(int if_index, in_addr_t ip) { 10 | uint8_t buffer[40] = { 11 | 0x46, 0xc0, 0x00, 0x28, 0x00, 0x00, 0x40, 0x00, 0x01, 0x02, // Header 12 | 0x00, 0x00, // Header checksum 13 | 0x00, 0x00, 0x00, 0x00, // Source 14 | 0xe0, 0x00, 0x00, 0x16, // IGMP Multicast 15 | 0x94, 0x04, 0x00, 0x00, // IP Option 16 | 0x22, // Membership Report 17 | 0x00, // Zeros 18 | 0xf9, 0xf4, // Checksum 19 | 0x00, 0x00, // Zeros 20 | 0x00, 0x01, // One Group Record 21 | 0x04, // Record Type 22 | 0x00, 0x00, 0x00, // Zeros 23 | 0xe0, 0x00, 0x00, 0x09 // RIP Multicast 24 | }; 25 | memcpy(&buffer[12], &ip, sizeof(in_addr_t)); 26 | uint32_t ip_chksum = 0; 27 | for (int i = 0; i < 12; i++) { 28 | ip_chksum += ((uint16_t *)buffer)[i]; 29 | } 30 | while (ip_chksum >= 0x10000) { 31 | ip_chksum -= 0x10000; 32 | ip_chksum += 1; 33 | } 34 | uint16_t chksum = ~ip_chksum; 35 | memcpy(&buffer[10], &chksum, sizeof(uint16_t)); 36 | macaddr_t dst_mac = {0x01, 0x00, 0x5e, 0x00, 0x00, 0x16}; 37 | HAL_SendIPPacket(if_index, buffer, sizeof(buffer), dst_mac); 38 | } 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /HAL/src/linux/platform/standard.h: -------------------------------------------------------------------------------- 1 | #include "router_hal.h" 2 | 3 | // configure this to match the output of `ip a` 4 | const char *interfaces[N_IFACE_ON_BOARD] = { 5 | "eth1", 6 | "eth2", 7 | "eth3", 8 | "eth4", 9 | }; 10 | -------------------------------------------------------------------------------- /HAL/src/linux/platform/testing.h: -------------------------------------------------------------------------------- 1 | #include "router_hal.h" 2 | 3 | // to use this, please define HAL_PLATFORM_TESTING 4 | // configure this to match the output of `ip a` 5 | const char *interfaces[N_IFACE_ON_BOARD] = { 6 | "lan0", 7 | "lan1", 8 | "enp0s31f6", 9 | "eth3", 10 | }; 11 | -------------------------------------------------------------------------------- /HAL/src/linux/router_hal.cpp: -------------------------------------------------------------------------------- 1 | #include "router_hal.h" 2 | #include "router_hal_common.h" 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #ifndef HAL_PLATFORM_TESTING 20 | #include "platform/standard.h" 21 | #else 22 | #include "platform/testing.h" 23 | #endif 24 | 25 | const int IP_OFFSET = 14; 26 | 27 | bool inited = false; 28 | int debugEnabled = 0; 29 | in_addr_t interface_addrs[N_IFACE_ON_BOARD] = {0}; 30 | macaddr_t interface_mac[N_IFACE_ON_BOARD] = {0}; 31 | 32 | pcap_t *pcap_in_handles[N_IFACE_ON_BOARD]; 33 | pcap_t *pcap_out_handles[N_IFACE_ON_BOARD]; 34 | 35 | std::map, macaddr_t> arp_table; 36 | std::map, uint64_t> arp_timer; 37 | 38 | extern "C" { 39 | int HAL_Init(int debug, in_addr_t if_addrs[N_IFACE_ON_BOARD]) { 40 | if (inited) { 41 | return 0; 42 | } 43 | debugEnabled = debug; 44 | 45 | // find matching interfaces and get their MAC address 46 | struct ifaddrs *ifaddr, *ifa; 47 | if (getifaddrs(&ifaddr) < 0) { 48 | if (debugEnabled) { 49 | fprintf(stderr, "HAL_Init: getifaddrs failed with %s\n", strerror(errno)); 50 | } 51 | return HAL_ERR_UNKNOWN; 52 | } 53 | 54 | for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { 55 | if (ifa->ifa_addr == NULL) 56 | continue; 57 | for (int i = 0; i < N_IFACE_ON_BOARD; i++) { 58 | if (ifa->ifa_addr->sa_family == AF_PACKET && 59 | strcmp(ifa->ifa_name, interfaces[i]) == 0) { 60 | // found 61 | memcpy(interface_mac[i], 62 | ((struct sockaddr_ll *)ifa->ifa_addr)->sll_addr, 63 | sizeof(macaddr_t)); 64 | memcpy(arp_table[std::pair(if_addrs[i], i)], 65 | interface_mac[i], sizeof(macaddr_t)); 66 | if (debugEnabled) { 67 | fprintf(stderr, "HAL_Init: found MAC addr of interface %s\n", 68 | interfaces[i]); 69 | } 70 | break; 71 | } 72 | } 73 | } 74 | freeifaddrs(ifaddr); 75 | 76 | // init pcap handles 77 | char error_buffer[PCAP_ERRBUF_SIZE]; 78 | for (int i = 0; i < N_IFACE_ON_BOARD; i++) { 79 | pcap_in_handles[i] = 80 | pcap_open_live(interfaces[i], BUFSIZ, 1, 1, error_buffer); 81 | if (pcap_in_handles[i]) { 82 | pcap_setnonblock(pcap_in_handles[i], 1, error_buffer); 83 | if (debugEnabled) { 84 | fprintf(stderr, "HAL_Init: pcap capture enabled for %s\n", 85 | interfaces[i]); 86 | } 87 | } else { 88 | if (debugEnabled) { 89 | fprintf(stderr, 90 | "HAL_Init: pcap capture disabled for %s, either the interface " 91 | "does not exist or permission is denied\n", 92 | interfaces[i]); 93 | } 94 | } 95 | pcap_out_handles[i] = 96 | pcap_open_live(interfaces[i], BUFSIZ, 1, 0, error_buffer); 97 | } 98 | 99 | memcpy(interface_addrs, if_addrs, sizeof(interface_addrs)); 100 | 101 | inited = true; 102 | // send igmp to join RIP multicast group 103 | for (int i = 0; i < N_IFACE_ON_BOARD; i++) { 104 | if (pcap_out_handles[i]) { 105 | HAL_JoinIGMPGroup(i, if_addrs[i]); 106 | if (debugEnabled) { 107 | fprintf(stderr, "HAL_Init: Joining RIP multicast group 224.0.0.9 for %s\n", 108 | interfaces[i]); 109 | } 110 | } 111 | } 112 | return 0; 113 | } 114 | 115 | uint64_t HAL_GetTicks() { 116 | struct timespec tp = {0}; 117 | clock_gettime(CLOCK_MONOTONIC, &tp); 118 | // millisecond 119 | return (uint64_t)tp.tv_sec * 1000 + (uint64_t)tp.tv_nsec / 1000000; 120 | } 121 | 122 | int HAL_ArpGetMacAddress(int if_index, in_addr_t ip, macaddr_t o_mac) { 123 | if (!inited) { 124 | return HAL_ERR_CALLED_BEFORE_INIT; 125 | } 126 | if (if_index >= N_IFACE_ON_BOARD || if_index < 0) { 127 | return HAL_ERR_INVALID_PARAMETER; 128 | } 129 | 130 | // handle multicast 131 | if ((ip & 0xe0) == 0xe0) { 132 | uint8_t multicasting_mac[6] = {0x01, 0, 0x5e, (uint8_t)((ip >> 8) & 0x7f), (uint8_t)(ip >> 16), (uint8_t)(ip >> 24)}; 133 | memcpy(o_mac, multicasting_mac, sizeof(macaddr_t)); 134 | return 0; 135 | } 136 | 137 | // lookup arp table 138 | auto it = arp_table.find(std::pair(ip, if_index)); 139 | if (it != arp_table.end()) { 140 | memcpy(o_mac, it->second, sizeof(macaddr_t)); 141 | return 0; 142 | } else if (pcap_out_handles[if_index] && 143 | arp_timer[std::pair(ip, if_index)] + 1000 < 144 | HAL_GetTicks()) { 145 | // not found, send arp request 146 | // rate limit arp request by 1 req/s 147 | arp_timer[std::pair(ip, if_index)] = HAL_GetTicks(); 148 | if (debugEnabled) { 149 | fprintf( 150 | stderr, 151 | "HAL_ArpGetMacAddress: asking for ip address %s with arp request\n", 152 | inet_ntoa(in_addr{ip})); 153 | } 154 | uint8_t buffer[64] = {0}; 155 | // dst mac 156 | for (int i = 0; i < 6; i++) { 157 | buffer[i] = 0xff; 158 | } 159 | // src mac 160 | macaddr_t mac; 161 | HAL_GetInterfaceMacAddress(if_index, mac); 162 | memcpy(&buffer[6], mac, sizeof(macaddr_t)); 163 | // ARP 164 | buffer[12] = 0x08; 165 | buffer[13] = 0x06; 166 | // hardware type 167 | buffer[15] = 0x01; 168 | // protocol type 169 | buffer[16] = 0x08; 170 | // hardware size 171 | buffer[18] = 0x06; 172 | // protocol size 173 | buffer[19] = 0x04; 174 | // opcode 175 | buffer[21] = 0x01; 176 | // sender 177 | memcpy(&buffer[22], mac, sizeof(macaddr_t)); 178 | memcpy(&buffer[28], &interface_addrs[if_index], sizeof(in_addr_t)); 179 | // target 180 | memcpy(&buffer[38], &ip, sizeof(in_addr_t)); 181 | 182 | pcap_inject(pcap_out_handles[if_index], buffer, sizeof(buffer)); 183 | } 184 | return HAL_ERR_IP_NOT_EXIST; 185 | } 186 | 187 | int HAL_GetInterfaceMacAddress(int if_index, macaddr_t o_mac) { 188 | if (!inited) { 189 | return HAL_ERR_CALLED_BEFORE_INIT; 190 | } 191 | if (if_index >= N_IFACE_ON_BOARD || if_index < 0) { 192 | return HAL_ERR_IFACE_NOT_EXIST; 193 | } 194 | 195 | memcpy(o_mac, interface_mac[if_index], sizeof(macaddr_t)); 196 | return 0; 197 | } 198 | 199 | int HAL_ReceiveIPPacket(int if_index_mask, uint8_t *buffer, size_t length, 200 | macaddr_t src_mac, macaddr_t dst_mac, int64_t timeout, 201 | int *if_index) { 202 | if (!inited) { 203 | return HAL_ERR_CALLED_BEFORE_INIT; 204 | } 205 | if ((if_index_mask & ((1 << N_IFACE_ON_BOARD) - 1)) == 0 || 206 | (timeout < 0 && timeout != -1) || (if_index == NULL) || (buffer == NULL)) { 207 | return HAL_ERR_INVALID_PARAMETER; 208 | } 209 | 210 | bool flag = false; 211 | for (int i = 0; i < N_IFACE_ON_BOARD; i++) { 212 | if (pcap_in_handles[i] && (if_index_mask & (1 << i))) { 213 | flag = true; 214 | } 215 | } 216 | if (!flag) { 217 | if (debugEnabled) { 218 | fprintf(stderr, 219 | "HAL_ReceiveIPPacket: no viable interfaces open for capture\n"); 220 | } 221 | return HAL_ERR_IFACE_NOT_EXIST; 222 | } 223 | 224 | int64_t begin = HAL_GetTicks(); 225 | int64_t current_time = 0; 226 | // Round robin 227 | int current_port = 0; 228 | struct pcap_pkthdr hdr; 229 | do { 230 | if ((if_index_mask & (1 << current_port)) == 0 || 231 | !pcap_in_handles[current_port]) { 232 | current_port = (current_port + 1) % N_IFACE_ON_BOARD; 233 | continue; 234 | } 235 | 236 | const uint8_t *packet = pcap_next(pcap_in_handles[current_port], &hdr); 237 | if (packet && hdr.caplen >= IP_OFFSET && 238 | memcmp(&packet[6], interface_mac[current_port], sizeof(macaddr_t)) == 239 | 0) { 240 | // skip outbound 241 | continue; 242 | } else if (packet && hdr.caplen >= IP_OFFSET && packet[12] == 0x08 && 243 | packet[13] == 0x00) { 244 | // IPv4 245 | // TODO: what if len != caplen 246 | // Beware: might be larger than MTU because of offloading 247 | size_t ip_len = hdr.caplen - IP_OFFSET; 248 | size_t real_length = length > ip_len ? ip_len : length; 249 | memcpy(buffer, &packet[IP_OFFSET], real_length); 250 | memcpy(dst_mac, &packet[0], sizeof(macaddr_t)); 251 | memcpy(src_mac, &packet[6], sizeof(macaddr_t)); 252 | *if_index = current_port; 253 | return ip_len; 254 | } else if (packet && hdr.caplen >= IP_OFFSET && packet[12] == 0x08 && 255 | packet[13] == 0x06) { 256 | // ARP 257 | // learn it 258 | macaddr_t mac; 259 | memcpy(mac, &packet[22], sizeof(macaddr_t)); 260 | in_addr_t ip; 261 | memcpy(&ip, &packet[28], sizeof(in_addr_t)); 262 | memcpy(arp_table[std::pair(ip, current_port)], mac, 263 | sizeof(macaddr_t)); 264 | if (debugEnabled) { 265 | fprintf(stderr, "HAL_ReceiveIPPacket: learned MAC address of %s\n", 266 | inet_ntoa(in_addr{ip})); 267 | } 268 | 269 | in_addr_t dst_ip; 270 | memcpy(&dst_ip, &packet[38], sizeof(in_addr_t)); 271 | // ask me: reply 272 | if (dst_ip == interface_addrs[current_port] && packet[21] == 0x01) { 273 | // reply 274 | uint8_t buffer[64] = {0}; 275 | // dst mac 276 | memcpy(buffer, &packet[6], sizeof(macaddr_t)); 277 | // src mac 278 | macaddr_t mac; 279 | HAL_GetInterfaceMacAddress(current_port, mac); 280 | memcpy(&buffer[6], mac, sizeof(macaddr_t)); 281 | // ARP 282 | buffer[12] = 0x08; 283 | buffer[13] = 0x06; 284 | // hardware type 285 | buffer[15] = 0x01; 286 | // protocol type 287 | buffer[16] = 0x08; 288 | // hardware size 289 | buffer[18] = 0x06; 290 | // protocol size 291 | buffer[19] = 0x04; 292 | // opcode 293 | buffer[21] = 0x02; 294 | // sender 295 | memcpy(&buffer[22], mac, sizeof(macaddr_t)); 296 | memcpy(&buffer[28], &dst_ip, sizeof(in_addr_t)); 297 | // target 298 | memcpy(&buffer[32], &packet[22], sizeof(macaddr_t)); 299 | memcpy(&buffer[38], &packet[28], sizeof(in_addr_t)); 300 | 301 | pcap_inject(pcap_out_handles[current_port], buffer, sizeof(buffer)); 302 | if (debugEnabled) { 303 | fprintf(stderr, "HAL_ReceiveIPPacket: replied ARP to %s\n", 304 | inet_ntoa(in_addr{ip})); 305 | } 306 | } 307 | // otherwise: learn and ignore 308 | continue; 309 | } 310 | 311 | current_port = (current_port + 1) % N_IFACE_ON_BOARD; 312 | // -1 for infinity 313 | } while ((current_time = HAL_GetTicks()) < begin + timeout || timeout == -1); 314 | return 0; 315 | } 316 | 317 | int HAL_SendIPPacket(int if_index, uint8_t *buffer, size_t length, 318 | macaddr_t dst_mac) { 319 | if (!inited) { 320 | return HAL_ERR_CALLED_BEFORE_INIT; 321 | } 322 | if (if_index >= N_IFACE_ON_BOARD || if_index < 0) { 323 | return HAL_ERR_INVALID_PARAMETER; 324 | } 325 | if (!pcap_out_handles[if_index]) { 326 | return HAL_ERR_IFACE_NOT_EXIST; 327 | } 328 | uint8_t *eth_buffer = (uint8_t *)malloc(length + IP_OFFSET); 329 | memcpy(eth_buffer, dst_mac, sizeof(macaddr_t)); 330 | memcpy(ð_buffer[6], interface_mac[if_index], sizeof(macaddr_t)); 331 | // IPv4 332 | eth_buffer[12] = 0x08; 333 | eth_buffer[13] = 0x00; 334 | memcpy(ð_buffer[IP_OFFSET], buffer, length); 335 | if (pcap_inject(pcap_out_handles[if_index], eth_buffer, length + IP_OFFSET) >= 336 | 0) { 337 | free(eth_buffer); 338 | return 0; 339 | } else { 340 | if (debugEnabled) { 341 | fprintf(stderr, "HAL_SendIPPacket: pcap_inject failed with %s\n", 342 | pcap_geterr(pcap_out_handles[if_index])); 343 | } 344 | free(eth_buffer); 345 | return HAL_ERR_UNKNOWN; 346 | } 347 | } 348 | } 349 | -------------------------------------------------------------------------------- /HAL/src/macOS/router_hal.cpp: -------------------------------------------------------------------------------- 1 | #include "router_hal.h" 2 | #include "router_hal_common.h" 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | const int IP_OFFSET = 14; 22 | 23 | const char *interfaces[N_IFACE_ON_BOARD] = { 24 | "en0", 25 | "en1", 26 | "en2", 27 | "en3", 28 | }; 29 | 30 | bool inited = false; 31 | int debugEnabled = 0; 32 | in_addr_t interface_addrs[N_IFACE_ON_BOARD] = {0}; 33 | macaddr_t interface_mac[N_IFACE_ON_BOARD] = {0}; 34 | 35 | pcap_t *pcap_in_handles[N_IFACE_ON_BOARD]; 36 | pcap_t *pcap_out_handles[N_IFACE_ON_BOARD]; 37 | 38 | // workaround for clang 39 | struct macaddr_wrap { 40 | macaddr_t mac; 41 | }; 42 | 43 | std::map, macaddr_wrap> arp_table; 44 | std::map, uint64_t> arp_timer; 45 | 46 | extern "C" { 47 | int HAL_Init(int debug, in_addr_t if_addrs[N_IFACE_ON_BOARD]) { 48 | if (inited) { 49 | return 0; 50 | } 51 | debugEnabled = debug; 52 | 53 | struct ifaddrs *ifaddr, *ifa; 54 | if (getifaddrs(&ifaddr) < 0) { 55 | if (debugEnabled) { 56 | fprintf(stderr, "HAL_Init: getifaddrs failed with %s\n", strerror(errno)); 57 | } 58 | return HAL_ERR_UNKNOWN; 59 | } 60 | 61 | // ref: 62 | // https://stackoverflow.com/questions/10593736/mac-address-from-interface-on-os-x-c 63 | for (int i = 0; i < N_IFACE_ON_BOARD; i++) { 64 | int index; 65 | if ((index = if_nametoindex(interfaces[i])) == 0) { 66 | if (debugEnabled) { 67 | fprintf(stderr, "HAL_Init: get MAC addr failed for interface %s\n", 68 | interfaces[i]); 69 | } 70 | continue; 71 | } 72 | 73 | int mib[6]; 74 | mib[0] = CTL_NET; 75 | mib[1] = AF_ROUTE; 76 | mib[2] = 0; 77 | mib[3] = AF_LINK; 78 | mib[4] = NET_RT_IFLIST; 79 | mib[5] = index; 80 | 81 | size_t len; 82 | 83 | if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { 84 | if (debugEnabled) { 85 | fprintf(stderr, "HAL_Init: get MAC addr failed for interface %s\n", 86 | interfaces[i]); 87 | } 88 | continue; 89 | } 90 | char *buf; 91 | 92 | if ((buf = (char *)malloc(len)) == NULL) { 93 | if (debugEnabled) { 94 | fprintf(stderr, "HAL_Init: get MAC addr failed for interface %s\n", 95 | interfaces[i]); 96 | } 97 | continue; 98 | } 99 | 100 | if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { 101 | if (debugEnabled) { 102 | fprintf(stderr, "HAL_Init: get MAC addr failed for interface %s\n", 103 | interfaces[i]); 104 | } 105 | continue; 106 | } 107 | 108 | struct if_msghdr *ifm = (struct if_msghdr *)buf; 109 | struct sockaddr_dl *sdl = (struct sockaddr_dl *)(ifm + 1); 110 | caddr_t mac = LLADDR(sdl); 111 | // found 112 | memcpy(interface_mac[i], mac, sizeof(macaddr_t)); 113 | memcpy(&arp_table[std::pair(if_addrs[i], i)], 114 | interface_mac[i], sizeof(macaddr_t)); 115 | if (debugEnabled) { 116 | macaddr_t m; 117 | // handle signedness 118 | memcpy(m, &mac, sizeof(macaddr_t)); 119 | fprintf(stderr, 120 | "HAL_Init: MAC addr of interface %s is " 121 | "%02X:%02X:%02X:%02X:%02X:%02X\n", 122 | interfaces[i], m[0], m[1], m[2], m[3], m[4], m[5]); 123 | } 124 | } 125 | 126 | char error_buffer[PCAP_ERRBUF_SIZE]; 127 | for (int i = 0; i < N_IFACE_ON_BOARD; i++) { 128 | pcap_in_handles[i] = 129 | pcap_open_live(interfaces[i], BUFSIZ, 1, 1, error_buffer); 130 | if (pcap_in_handles[i]) { 131 | pcap_setnonblock(pcap_in_handles[i], 1, error_buffer); 132 | if (debugEnabled) { 133 | fprintf(stderr, "HAL_Init: pcap capture enabled for %s\n", 134 | interfaces[i]); 135 | } 136 | } else { 137 | if (debugEnabled) { 138 | fprintf(stderr, 139 | "HAL_Init: pcap capture disabled for %s, either the interface " 140 | "does not exist or permission is denied\n", 141 | interfaces[i]); 142 | } 143 | } 144 | pcap_out_handles[i] = 145 | pcap_open_live(interfaces[i], BUFSIZ, 1, 0, error_buffer); 146 | } 147 | 148 | memcpy(interface_addrs, if_addrs, sizeof(interface_addrs)); 149 | 150 | inited = true; 151 | for (int i = 0; i < N_IFACE_ON_BOARD; i++) { 152 | if (pcap_out_handles[i]) { 153 | HAL_JoinIGMPGroup(i, if_addrs[i]); 154 | if (debugEnabled) { 155 | fprintf(stderr, "HAL_Init: Joining RIP multicast group 224.0.0.9 for %s\n", 156 | interfaces[i]); 157 | } 158 | } 159 | } 160 | return 0; 161 | } 162 | 163 | uint64_t HAL_GetTicks() { 164 | struct timespec tp = {0}; 165 | clock_gettime(CLOCK_MONOTONIC, &tp); 166 | return (uint64_t)tp.tv_sec * 1000 + (uint64_t)tp.tv_nsec / 1000000; 167 | } 168 | 169 | int HAL_ArpGetMacAddress(int if_index, in_addr_t ip, macaddr_t o_mac) { 170 | if (!inited) { 171 | return HAL_ERR_CALLED_BEFORE_INIT; 172 | } 173 | if (if_index >= N_IFACE_ON_BOARD || if_index < 0) { 174 | return HAL_ERR_INVALID_PARAMETER; 175 | } 176 | 177 | if ((ip & 0xe0) == 0xe0) { 178 | uint8_t multicasting_mac[6] = {0x01, 0, 0x5e, (uint8_t)((ip >> 8) & 0x7f), (uint8_t)(ip >> 16), (uint8_t)(ip >> 24)}; 179 | memcpy(o_mac, multicasting_mac, sizeof(macaddr_t)); 180 | return 0; 181 | } 182 | 183 | auto it = arp_table.find(std::pair(ip, if_index)); 184 | if (it != arp_table.end()) { 185 | memcpy(o_mac, &it->second, sizeof(macaddr_t)); 186 | return 0; 187 | } else if (pcap_out_handles[if_index] && 188 | arp_timer[std::pair(ip, if_index)] + 1000 < 189 | HAL_GetTicks()) { 190 | arp_timer[std::pair(ip, if_index)] = HAL_GetTicks(); 191 | if (debugEnabled) { 192 | struct in_addr addr; 193 | addr.s_addr = ip; 194 | fprintf( 195 | stderr, 196 | "HAL_ArpGetMacAddress: asking for ip address %s with arp request\n", 197 | inet_ntoa(addr)); 198 | } 199 | uint8_t buffer[64] = {0}; 200 | // dst mac 201 | for (int i = 0; i < 6; i++) { 202 | buffer[i] = 0xff; 203 | } 204 | // src mac 205 | macaddr_t mac; 206 | HAL_GetInterfaceMacAddress(if_index, mac); 207 | memcpy(&buffer[6], mac, sizeof(macaddr_t)); 208 | // ARP 209 | buffer[12] = 0x08; 210 | buffer[13] = 0x06; 211 | // hardware type 212 | buffer[15] = 0x01; 213 | // protocol type 214 | buffer[16] = 0x08; 215 | // hardware size 216 | buffer[18] = 0x06; 217 | // protocol size 218 | buffer[19] = 0x04; 219 | // opcode 220 | buffer[21] = 0x01; 221 | // sender 222 | memcpy(&buffer[22], mac, sizeof(macaddr_t)); 223 | memcpy(&buffer[28], &interface_addrs[if_index], sizeof(in_addr_t)); 224 | // target 225 | memcpy(&buffer[38], &ip, sizeof(in_addr_t)); 226 | 227 | pcap_inject(pcap_out_handles[if_index], buffer, sizeof(buffer)); 228 | } 229 | return HAL_ERR_IP_NOT_EXIST; 230 | } 231 | 232 | int HAL_GetInterfaceMacAddress(int if_index, macaddr_t o_mac) { 233 | if (!inited) { 234 | return HAL_ERR_CALLED_BEFORE_INIT; 235 | } 236 | if (if_index >= N_IFACE_ON_BOARD || if_index < 0) { 237 | return HAL_ERR_IFACE_NOT_EXIST; 238 | } 239 | 240 | memcpy(o_mac, interface_mac[if_index], sizeof(macaddr_t)); 241 | return 0; 242 | } 243 | 244 | int HAL_ReceiveIPPacket(int if_index_mask, uint8_t *buffer, size_t length, 245 | macaddr_t src_mac, macaddr_t dst_mac, int64_t timeout, 246 | int *if_index) { 247 | if (!inited) { 248 | return HAL_ERR_CALLED_BEFORE_INIT; 249 | } 250 | if ((if_index_mask & ((1 << N_IFACE_ON_BOARD) - 1)) == 0 || 251 | (timeout < 0 && timeout != -1) || (if_index == NULL)) { 252 | return HAL_ERR_INVALID_PARAMETER; 253 | } 254 | 255 | bool flag = false; 256 | for (int i = 0; i < N_IFACE_ON_BOARD; i++) { 257 | if (pcap_in_handles[i] && (if_index_mask & (1 << i))) { 258 | flag = true; 259 | } 260 | } 261 | if (!flag) { 262 | if (debugEnabled) { 263 | fprintf(stderr, 264 | "HAL_ReceiveIPPacket: no viable interfaces open for capture\n"); 265 | } 266 | return HAL_ERR_IFACE_NOT_EXIST; 267 | } 268 | 269 | int64_t begin = HAL_GetTicks(); 270 | int64_t current_time = 0; 271 | // Round robin 272 | int current_port = 0; 273 | struct pcap_pkthdr hdr; 274 | do { 275 | if ((if_index_mask & (1 << current_port)) == 0 || 276 | !pcap_in_handles[current_port]) { 277 | current_port = (current_port + 1) % N_IFACE_ON_BOARD; 278 | continue; 279 | } 280 | 281 | const uint8_t *packet = pcap_next(pcap_in_handles[current_port], &hdr); 282 | if (packet && hdr.caplen >= IP_OFFSET && 283 | memcmp(&packet[6], interface_mac[current_port], sizeof(macaddr_t)) == 284 | 0) { 285 | // skip outbound 286 | continue; 287 | } else if (packet && hdr.caplen >= IP_OFFSET && packet[12] == 0x08 && 288 | packet[13] == 0x00) { 289 | // IPv4 290 | // TODO: what if len != caplen 291 | size_t ip_len = hdr.caplen - IP_OFFSET; 292 | size_t real_length = length > ip_len ? ip_len : length; 293 | memcpy(buffer, &packet[IP_OFFSET], real_length); 294 | memcpy(dst_mac, &packet[0], sizeof(macaddr_t)); 295 | memcpy(src_mac, &packet[6], sizeof(macaddr_t)); 296 | *if_index = current_port; 297 | return ip_len; 298 | } else if (packet && hdr.caplen >= IP_OFFSET && packet[12] == 0x08 && 299 | packet[13] == 0x06) { 300 | // ARP 301 | macaddr_t mac; 302 | memcpy(mac, &packet[22], sizeof(macaddr_t)); 303 | in_addr_t ip; 304 | memcpy(&ip, &packet[28], sizeof(in_addr_t)); 305 | memcpy(&arp_table[std::pair(ip, current_port)], mac, 306 | sizeof(macaddr_t)); 307 | if (debugEnabled) { 308 | struct in_addr addr; 309 | addr.s_addr = ip; 310 | fprintf(stderr, "HAL_ReceiveIPPacket: learned MAC address of %s\n", 311 | inet_ntoa(addr)); 312 | } 313 | 314 | in_addr_t dst_ip; 315 | memcpy(&dst_ip, &packet[38], sizeof(in_addr_t)); 316 | if (dst_ip == interface_addrs[current_port] && packet[21] == 0x01) { 317 | // reply 318 | uint8_t buffer[64] = {0}; 319 | // dst mac 320 | memcpy(buffer, &packet[6], sizeof(macaddr_t)); 321 | // src mac 322 | macaddr_t mac; 323 | HAL_GetInterfaceMacAddress(current_port, mac); 324 | memcpy(&buffer[6], mac, sizeof(macaddr_t)); 325 | // ARP 326 | buffer[12] = 0x08; 327 | buffer[13] = 0x06; 328 | // hardware type 329 | buffer[15] = 0x01; 330 | // protocol type 331 | buffer[16] = 0x08; 332 | // hardware size 333 | buffer[18] = 0x06; 334 | // protocol size 335 | buffer[19] = 0x04; 336 | // opcode 337 | buffer[21] = 0x02; 338 | // sender 339 | memcpy(&buffer[22], mac, sizeof(macaddr_t)); 340 | memcpy(&buffer[28], &dst_ip, sizeof(in_addr_t)); 341 | // target 342 | memcpy(&buffer[32], &packet[22], sizeof(macaddr_t)); 343 | memcpy(&buffer[38], &packet[28], sizeof(in_addr_t)); 344 | 345 | pcap_inject(pcap_out_handles[current_port], buffer, sizeof(buffer)); 346 | if (debugEnabled) { 347 | struct in_addr addr; 348 | addr.s_addr = ip; 349 | fprintf(stderr, "HAL_ReceiveIPPacket: replied ARP to %s\n", 350 | inet_ntoa(addr)); 351 | } 352 | } 353 | continue; 354 | } 355 | 356 | current_port = (current_port + 1) % N_IFACE_ON_BOARD; 357 | // -1 for infinity 358 | } while ((current_time = HAL_GetTicks()) < begin + timeout || timeout == -1); 359 | return 0; 360 | } 361 | 362 | int HAL_SendIPPacket(int if_index, uint8_t *buffer, size_t length, 363 | macaddr_t dst_mac) { 364 | if (!inited) { 365 | return HAL_ERR_CALLED_BEFORE_INIT; 366 | } 367 | if (if_index >= N_IFACE_ON_BOARD || if_index < 0) { 368 | return HAL_ERR_INVALID_PARAMETER; 369 | } 370 | if (!pcap_out_handles[if_index]) { 371 | return HAL_ERR_IFACE_NOT_EXIST; 372 | } 373 | uint8_t *eth_buffer = (uint8_t *)malloc(length + IP_OFFSET); 374 | memcpy(eth_buffer, dst_mac, sizeof(macaddr_t)); 375 | memcpy(ð_buffer[6], interface_mac[if_index], sizeof(macaddr_t)); 376 | // IPv4 377 | eth_buffer[12] = 0x08; 378 | eth_buffer[13] = 0x00; 379 | memcpy(ð_buffer[IP_OFFSET], buffer, length); 380 | if (pcap_inject(pcap_out_handles[if_index], eth_buffer, length + IP_OFFSET) >= 381 | 0) { 382 | free(eth_buffer); 383 | return 0; 384 | } else { 385 | if (debugEnabled) { 386 | fprintf(stderr, "HAL_SendIPPacket: pcap_inject failed with %s\n", 387 | pcap_geterr(pcap_out_handles[if_index])); 388 | } 389 | free(eth_buffer); 390 | return HAL_ERR_UNKNOWN; 391 | } 392 | } 393 | } 394 | -------------------------------------------------------------------------------- /HAL/src/stdio/router_hal.cpp: -------------------------------------------------------------------------------- 1 | #include "router_hal.h" 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | const int IP_OFFSET = 18; // 6 + 6 + 4 + 2 12 | 13 | bool inited = false; 14 | bool outputInited = false; 15 | int debugEnabled = 0; 16 | in_addr_t interface_addrs[N_IFACE_ON_BOARD] = {0}; 17 | macaddr_t interface_mac[N_IFACE_ON_BOARD] = {0}; 18 | 19 | // input 20 | pcap_t *pcap_handle; 21 | 22 | // output 23 | pcap_t *pcap_out_handle; 24 | pcap_dumper_t *pcap_dumper; 25 | 26 | // workaround for clang 27 | struct macaddr_wrap { 28 | macaddr_t mac; 29 | }; 30 | 31 | std::map, macaddr_wrap> arp_table; 32 | 33 | extern "C" { 34 | int HAL_Init(int debug, in_addr_t if_addrs[N_IFACE_ON_BOARD]) { 35 | if (inited) { 36 | return 0; 37 | } 38 | debugEnabled = debug; 39 | 40 | for (int i = 0; i < N_IFACE_ON_BOARD; i++) { 41 | // hard coded MAC 42 | macaddr_t mac = {2, 3, 3, 0, 0, (uint8_t)i}; 43 | memcpy(interface_mac[i], mac, sizeof(macaddr_t)); 44 | memcpy(&arp_table[std::pair(if_addrs[i], i)], 45 | interface_mac[i], sizeof(macaddr_t)); 46 | } 47 | 48 | char error_buffer[PCAP_ERRBUF_SIZE]; 49 | 50 | // input 51 | pcap_handle = pcap_open_offline("-", error_buffer); 52 | if (!pcap_handle) { 53 | if (debugEnabled) { 54 | fprintf(stderr, "pcap_open_offline failed with %s", error_buffer); 55 | } 56 | return HAL_ERR_UNKNOWN; 57 | } 58 | 59 | memcpy(interface_addrs, if_addrs, sizeof(interface_addrs)); 60 | 61 | inited = true; 62 | return 0; 63 | } 64 | 65 | uint64_t HAL_GetTicks() { 66 | struct timespec tp = {0}; 67 | clock_gettime(CLOCK_MONOTONIC, &tp); 68 | return (uint64_t)tp.tv_sec * 1000 + (uint64_t)tp.tv_nsec / 1000000; 69 | } 70 | 71 | int HAL_ArpGetMacAddress(int if_index, in_addr_t ip, macaddr_t o_mac) { 72 | if (!inited) { 73 | return HAL_ERR_CALLED_BEFORE_INIT; 74 | } 75 | if (if_index >= N_IFACE_ON_BOARD || if_index < 0) { 76 | return HAL_ERR_INVALID_PARAMETER; 77 | } 78 | 79 | if ((ip & 0xe0) == 0xe0) { 80 | uint8_t multicasting_mac[6] = {0x01, 0, 0x5e, (uint8_t)((ip >> 8) & 0x7f), (uint8_t)(ip >> 16), (uint8_t)(ip >> 24)}; 81 | memcpy(o_mac, multicasting_mac, sizeof(macaddr_t)); 82 | return 0; 83 | } 84 | 85 | auto it = arp_table.find(std::pair(ip, if_index)); 86 | if (it != arp_table.end()) { 87 | memcpy(o_mac, &it->second, sizeof(macaddr_t)); 88 | return 0; 89 | } else { 90 | if (debugEnabled) { 91 | struct in_addr addr; 92 | addr.s_addr = ip; 93 | fprintf( 94 | stderr, 95 | "HAL_ArpGetMacAddress: asking for ip address %s with arp request\n", 96 | inet_ntoa(addr)); 97 | } 98 | uint8_t buffer[64] = {0}; 99 | // dst mac = broadcast 100 | for (int i = 0; i < 6; i++) { 101 | buffer[i] = 0xff; 102 | } 103 | // src mac 104 | macaddr_t mac; 105 | HAL_GetInterfaceMacAddress(if_index, mac); 106 | memcpy(&buffer[6], mac, sizeof(macaddr_t)); 107 | // 802.1Q 108 | buffer[12] = 0x81; 109 | buffer[13] = 0x00; 110 | buffer[14] = 0x00; 111 | buffer[15] = if_index; 112 | // ARP 113 | buffer[16] = 0x08; 114 | buffer[17] = 0x06; 115 | // hardware type 116 | buffer[19] = 0x01; 117 | // protocol type 118 | buffer[20] = 0x08; 119 | // hardware size 120 | buffer[22] = 0x06; 121 | // protocol size 122 | buffer[23] = 0x04; 123 | // opcode 124 | buffer[25] = 0x01; 125 | // sender 126 | memcpy(&buffer[26], mac, sizeof(macaddr_t)); 127 | memcpy(&buffer[32], &interface_addrs[if_index], sizeof(in_addr_t)); 128 | // target 129 | memcpy(&buffer[42], &ip, sizeof(in_addr_t)); 130 | 131 | struct pcap_pkthdr header; 132 | header.caplen = header.len = sizeof(buffer); 133 | 134 | struct timespec tp = {0}; 135 | clock_gettime(CLOCK_MONOTONIC, &tp); 136 | header.ts.tv_sec = tp.tv_sec; 137 | header.ts.tv_usec = tp.tv_nsec / 1000; 138 | 139 | if (!outputInited) { 140 | // output 141 | pcap_out_handle = pcap_open_dead(DLT_EN10MB, 0x40000); 142 | pcap_dumper = pcap_dump_open(pcap_out_handle, "-"); 143 | outputInited = true; 144 | } 145 | pcap_dump((u_char *)pcap_dumper, &header, buffer); 146 | } 147 | return HAL_ERR_IP_NOT_EXIST; 148 | } 149 | 150 | int HAL_GetInterfaceMacAddress(int if_index, macaddr_t o_mac) { 151 | if (!inited) { 152 | return HAL_ERR_CALLED_BEFORE_INIT; 153 | } 154 | if (if_index >= N_IFACE_ON_BOARD || if_index < 0) { 155 | return HAL_ERR_IFACE_NOT_EXIST; 156 | } 157 | 158 | memcpy(o_mac, interface_mac[if_index], sizeof(macaddr_t)); 159 | return 0; 160 | } 161 | 162 | int HAL_ReceiveIPPacket(int if_index_mask, uint8_t *buffer, size_t length, 163 | macaddr_t src_mac, macaddr_t dst_mac, int64_t timeout, 164 | int *if_index) { 165 | if (!inited) { 166 | return HAL_ERR_CALLED_BEFORE_INIT; 167 | } 168 | if ((if_index_mask & ((1 << N_IFACE_ON_BOARD) - 1)) == 0 || 169 | (timeout < 0 && timeout != -1) || (if_index == NULL)) { 170 | return HAL_ERR_INVALID_PARAMETER; 171 | } 172 | 173 | int64_t begin = HAL_GetTicks(); 174 | int64_t current_time = 0; 175 | 176 | struct pcap_pkthdr *hdr; 177 | const u_char *packet; 178 | do { 179 | int res = pcap_next_ex(pcap_handle, &hdr, &packet); 180 | if (res == PCAP_ERROR_BREAK) { 181 | return HAL_ERR_EOF; 182 | } else if (res != 1) { 183 | // retry 184 | continue; 185 | } 186 | 187 | // check 802.1Q 188 | if (packet && hdr->caplen >= IP_OFFSET && packet[12] == 0x81 && 189 | packet[13] == 0x00 && packet[14] == 0x00 && packet[15] >= 0 && 190 | packet[15] < N_IFACE_ON_BOARD) { 191 | int current_port = packet[15]; 192 | if (packet[16] == 0x08 && packet[17] == 0x00) { 193 | // IPv4 194 | // assuming len == caplen 195 | size_t ip_len = hdr->caplen - IP_OFFSET; 196 | size_t real_length = length > ip_len ? ip_len : length; 197 | memcpy(buffer, &packet[IP_OFFSET], real_length); 198 | memcpy(dst_mac, &packet[0], sizeof(macaddr_t)); 199 | memcpy(src_mac, &packet[6], sizeof(macaddr_t)); 200 | *if_index = current_port; 201 | return ip_len; 202 | } else if (packet[16] == 0x08 && packet[17] == 0x06) { 203 | // ARP 204 | macaddr_t mac; 205 | memcpy(mac, &packet[26], sizeof(macaddr_t)); 206 | in_addr_t ip; 207 | memcpy(&ip, &packet[32], sizeof(in_addr_t)); 208 | 209 | memcpy(&arp_table[std::pair(ip, current_port)], mac, 210 | sizeof(macaddr_t)); 211 | if (debugEnabled) { 212 | struct in_addr addr; 213 | addr.s_addr = ip; 214 | fprintf(stderr, "HAL_ReceiveIPPacket: learned MAC address of %s\n", 215 | inet_ntoa(addr)); 216 | } 217 | 218 | in_addr_t dst_ip; 219 | memcpy(&dst_ip, &packet[42], sizeof(in_addr_t)); 220 | if (dst_ip == interface_addrs[current_port] && packet[25] == 0x01) { 221 | // reply 222 | uint8_t buffer[64] = {0}; 223 | // dst mac 224 | memcpy(buffer, &packet[6], sizeof(macaddr_t)); 225 | // src mac 226 | macaddr_t mac; 227 | HAL_GetInterfaceMacAddress(current_port, mac); 228 | memcpy(&buffer[6], mac, sizeof(macaddr_t)); 229 | // VLAN 230 | buffer[12] = 0x81; 231 | buffer[13] = 0x00; 232 | buffer[14] = 0x00; 233 | buffer[15] = current_port; 234 | // ARP 235 | buffer[16] = 0x08; 236 | buffer[17] = 0x06; 237 | // hardware type 238 | buffer[19] = 0x01; 239 | // protocol type 240 | buffer[20] = 0x08; 241 | // hardware size 242 | buffer[22] = 0x06; 243 | // protocol size 244 | buffer[23] = 0x04; 245 | // opcode 246 | buffer[25] = 0x02; 247 | // sender 248 | memcpy(&buffer[26], mac, sizeof(macaddr_t)); 249 | memcpy(&buffer[32], &dst_ip, sizeof(in_addr_t)); 250 | // target 251 | memcpy(&buffer[36], &packet[22], sizeof(macaddr_t)); 252 | memcpy(&buffer[42], &packet[28], sizeof(in_addr_t)); 253 | 254 | struct pcap_pkthdr header; 255 | header.caplen = header.len = sizeof(buffer); 256 | 257 | struct timespec tp = {0}; 258 | clock_gettime(CLOCK_MONOTONIC, &tp); 259 | header.ts.tv_sec = tp.tv_sec; 260 | header.ts.tv_usec = tp.tv_nsec / 1000; 261 | 262 | if (!outputInited) { 263 | // output 264 | pcap_out_handle = pcap_open_dead(DLT_EN10MB, 0x40000); 265 | pcap_dumper = pcap_dump_open(pcap_out_handle, "-"); 266 | outputInited = true; 267 | } 268 | pcap_dump((u_char *)pcap_dumper, &header, buffer); 269 | 270 | if (debugEnabled) { 271 | struct in_addr addr; 272 | addr.s_addr = ip; 273 | fprintf(stderr, "HAL_ReceiveIPPacket: replied ARP to %s\n", 274 | inet_ntoa(addr)); 275 | } 276 | } 277 | continue; 278 | } 279 | } 280 | 281 | // -1 for infinity 282 | } while ((current_time = HAL_GetTicks()) < begin + timeout || timeout == -1); 283 | return 0; 284 | } 285 | 286 | int HAL_SendIPPacket(int if_index, uint8_t *buffer, size_t length, 287 | macaddr_t dst_mac) { 288 | if (!inited) { 289 | return HAL_ERR_CALLED_BEFORE_INIT; 290 | } 291 | if (if_index >= N_IFACE_ON_BOARD || if_index < 0) { 292 | return HAL_ERR_INVALID_PARAMETER; 293 | } 294 | uint8_t *eth_buffer = (uint8_t *)malloc(length + IP_OFFSET); 295 | memcpy(eth_buffer, dst_mac, sizeof(macaddr_t)); 296 | memcpy(ð_buffer[6], interface_mac[if_index], sizeof(macaddr_t)); 297 | // VLAN 298 | eth_buffer[12] = 0x81; 299 | eth_buffer[13] = 0x00; 300 | eth_buffer[14] = 0x00; 301 | eth_buffer[15] = if_index; 302 | // IPv4 303 | eth_buffer[16] = 0x08; 304 | eth_buffer[17] = 0x00; 305 | memcpy(ð_buffer[IP_OFFSET], buffer, length); 306 | struct pcap_pkthdr header; 307 | header.caplen = header.len = length + IP_OFFSET; 308 | 309 | struct timespec tp = {0}; 310 | clock_gettime(CLOCK_MONOTONIC, &tp); 311 | header.ts.tv_sec = tp.tv_sec; 312 | header.ts.tv_usec = tp.tv_nsec / 1000; 313 | 314 | if (!outputInited) { 315 | // output 316 | pcap_out_handle = pcap_open_dead(DLT_EN10MB, 0x40000); 317 | pcap_dumper = pcap_dump_open(pcap_out_handle, "-"); 318 | outputInited = true; 319 | } 320 | pcap_dump((u_char *)pcap_dumper, &header, eth_buffer); 321 | free(eth_buffer); 322 | return 0; 323 | } 324 | } 325 | -------------------------------------------------------------------------------- /HAL/src/xilinx/router_hal.c: -------------------------------------------------------------------------------- 1 | #include "router_hal.h" 2 | #include "xaxidma.h" 3 | #include "xaxiethernet.h" 4 | #include "xil_printf.h" 5 | #include "xspi.h" 6 | #include "xtmrctr.h" 7 | #include 8 | 9 | const int IP_OFFSET = 14 + 4; 10 | const int ARP_LENGTH = 28; 11 | 12 | int inited = 0; 13 | int debugEnabled = 0; 14 | in_addr_t interface_addrs[N_IFACE_ON_BOARD] = {0}; 15 | macaddr_t interface_mac = {2, 3, 3, 3, 3, 3}; 16 | 17 | XAxiEthernet_Config *axiEthernetConfig; 18 | XAxiDma_Config *axiDmaConfig; 19 | XSpi_Config *spiConfig; 20 | 21 | XAxiEthernet axiEthernet; 22 | XAxiDma axiDma; 23 | XSpi spi; 24 | XTmrCtr tmrCtr; 25 | 26 | XAxiDma_BdRing *rxRing; 27 | XAxiDma_BdRing *txRing; 28 | 29 | #define BD_COUNT 128 30 | 31 | char rxBdSpace[XAxiDma_BdRingMemCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT, BD_COUNT)] 32 | __attribute__((aligned(XAXIDMA_BD_MINIMUM_ALIGNMENT))) 33 | __attribute__((section(".physical"))); 34 | char txBdSpace[XAxiDma_BdRingMemCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT, BD_COUNT)] 35 | __attribute__((aligned(XAXIDMA_BD_MINIMUM_ALIGNMENT))) 36 | __attribute__((section(".physical"))); 37 | 38 | struct EthernetFrame { 39 | u8 dstMAC[6]; 40 | u8 srcMAC[6]; 41 | u16 vlanEtherType; 42 | u16 vlanID; 43 | u16 etherType; 44 | u8 data[1500]; 45 | }; 46 | 47 | struct EthernetFrame rxBuffers[BD_COUNT] __attribute__((section(".physical"))); 48 | struct EthernetFrame txBuffers[BD_COUNT] __attribute__((section(".physical"))); 49 | u32 txBufferUsed = 0; 50 | 51 | #define ARP_TABLE_SIZE 16 52 | 53 | // simple FIFO cache 54 | struct ArpTableEntry { 55 | int if_index; 56 | macaddr_t mac; 57 | in_addr_t ip; 58 | } arpTable[ARP_TABLE_SIZE]; 59 | 60 | void SpiWriteRegister(u8 addr, u8 data) { 61 | u8 writeBuffer[3]; 62 | // write 63 | writeBuffer[0] = 0x40 | (addr >> 7); 64 | writeBuffer[1] = addr << 1; 65 | writeBuffer[2] = data; 66 | XSpi_SetSlaveSelect(&spi, 1); 67 | XSpi_Transfer(&spi, writeBuffer, NULL, 3); 68 | if (debugEnabled) { 69 | xil_printf("HAL_Init: Write SPI %d = %d\r\n", addr, data); 70 | } 71 | } 72 | 73 | void PutBackBd(XAxiDma_Bd *bd) { 74 | u32 addr = XAxiDma_BdGetBufAddr(bd); 75 | u32 len = XAxiDma_BdGetLength(bd, rxRing->MaxTransferLen); 76 | XAxiDma_BdRingFree(rxRing, 1, bd); 77 | 78 | XAxiDma_BdRingAlloc(rxRing, 1, &bd); 79 | XAxiDma_BdSetBufAddr(bd, addr); 80 | XAxiDma_BdSetLength(bd, len, rxRing->MaxTransferLen); 81 | XAxiDma_BdRingToHw(rxRing, 1, bd); 82 | } 83 | 84 | void WaitTxBdAvailable() { 85 | XAxiDma_Bd *bd; 86 | while (txBufferUsed == BD_COUNT) { 87 | u32 count = XAxiDma_BdRingFromHw(txRing, BD_COUNT, &bd); 88 | if (count > 0) { 89 | XAxiDma_BdRingFree(txRing, count, bd); 90 | txBufferUsed -= count; 91 | break; 92 | } 93 | } 94 | } 95 | 96 | int HAL_Init(int debug, in_addr_t if_addrs[N_IFACE_ON_BOARD]) { 97 | XAxiDma_Bd *bd; 98 | if (inited) { 99 | return 0; 100 | } 101 | debugEnabled = debug; 102 | 103 | axiEthernetConfig = XAxiEthernet_LookupConfig(XPAR_AXI_ETHERNET_0_DEVICE_ID); 104 | axiDmaConfig = XAxiDma_LookupConfig(XPAR_AXIDMA_0_DEVICE_ID); 105 | spiConfig = XSpi_LookupConfig(XPAR_AXI_QUAD_SPI_0_DEVICE_ID); 106 | 107 | XAxiDma_CfgInitialize(&axiDma, axiDmaConfig); 108 | XAxiEthernet_CfgInitialize(&axiEthernet, axiEthernetConfig, 109 | axiEthernetConfig->BaseAddress); 110 | XSpi_CfgInitialize(&spi, spiConfig, spiConfig->BaseAddress); 111 | XTmrCtr_Initialize(&tmrCtr, XPAR_AXI_TIMER_0_DEVICE_ID); 112 | 113 | XTmrCtr_Start(&tmrCtr, 0); 114 | 115 | if (debugEnabled) { 116 | xil_printf("HAL_Init: Init vlan %x\n\r", rxBdSpace); 117 | } 118 | XSpi_SetOptions(&spi, XSP_MASTER_OPTION | XSP_MANUAL_SSELECT_OPTION); 119 | XSpi_Start(&spi); 120 | XSpi_IntrGlobalDisable(&spi); 121 | // P1-P4 Tag Removal 122 | SpiWriteRegister(16, 2); 123 | SpiWriteRegister(32, 2); 124 | SpiWriteRegister(48, 2); 125 | SpiWriteRegister(64, 2); 126 | // P5 Tag Insertion 127 | SpiWriteRegister(80, 4); 128 | // P1-P5 PVID 129 | SpiWriteRegister(20, 1); 130 | SpiWriteRegister(36, 2); 131 | SpiWriteRegister(52, 3); 132 | SpiWriteRegister(68, 4); 133 | SpiWriteRegister(84, 5); 134 | 135 | if (debugEnabled) { 136 | xil_printf("HAL_Init: Init rings @ %x\r\n", rxBdSpace); 137 | } 138 | rxRing = XAxiDma_GetRxRing(&axiDma); 139 | txRing = XAxiDma_GetTxRing(&axiDma); 140 | 141 | memset(rxBdSpace, 0, sizeof(rxBdSpace)); 142 | memset(txBdSpace, 0, sizeof(txBdSpace)); 143 | XAxiDma_BdRingCreate(rxRing, (UINTPTR)rxBdSpace, (UINTPTR)rxBdSpace, 144 | XAXIDMA_BD_MINIMUM_ALIGNMENT, BD_COUNT); 145 | XAxiDma_BdRingCreate(txRing, (UINTPTR)txBdSpace, (UINTPTR)txBdSpace, 146 | XAXIDMA_BD_MINIMUM_ALIGNMENT, BD_COUNT); 147 | 148 | if (debugEnabled) { 149 | xil_printf("HAL_Init: Enable Ethernet MAC\r\n"); 150 | } 151 | XAxiEthernet_SetOptions(&axiEthernet, XAE_RECEIVER_ENABLE_OPTION | 152 | XAE_TRANSMITTER_ENABLE_OPTION | XAE_VLAN_OPTION); 153 | XAxiEthernet_SetMacAddress(&axiEthernet, interface_mac); 154 | XAxiEthernet_Start(&axiEthernet); 155 | 156 | if (debugEnabled) { 157 | xil_printf("HAL_Init: Add buffer to rings\r\n"); 158 | } 159 | // rx 160 | for (int i = 0; i < BD_COUNT; i++) { 161 | XAxiDma_BdRingAlloc(rxRing, 1, &bd); 162 | XAxiDma_BdSetBufAddr(bd, (UINTPTR)&rxBuffers[i]); 163 | XAxiDma_BdSetLength(bd, sizeof(struct EthernetFrame), 164 | rxRing->MaxTransferLen); 165 | XAxiDma_BdRingToHw(rxRing, 1, bd); 166 | } 167 | 168 | // tx 169 | XAxiDma_BdRingAlloc(txRing, BD_COUNT, &bd); 170 | XAxiDma_Bd *firstBd = bd; 171 | for (int i = 0; i < BD_COUNT; i++) { 172 | XAxiDma_BdSetBufAddr(bd, (UINTPTR)&txBuffers[i]); 173 | bd = (XAxiDma_Bd *)XAxiDma_BdRingNext(txRing, bd); 174 | } 175 | XAxiDma_BdRingUnAlloc(txRing, BD_COUNT, firstBd); 176 | 177 | XAxiDma_BdRingStart(rxRing); 178 | XAxiDma_BdRingStart(txRing); 179 | 180 | memcpy(interface_addrs, if_addrs, sizeof(interface_addrs)); 181 | memset(arpTable, 0, sizeof(arpTable)); 182 | 183 | inited = 1; 184 | return 0; 185 | } 186 | 187 | uint64_t HAL_GetTicks() { 188 | // TODO 189 | return XTmrCtr_GetValue(&tmrCtr, 0) * 1000 / XPAR_AXI_TIMER_0_CLOCK_FREQ_HZ; 190 | } 191 | 192 | int HAL_ArpGetMacAddress(int if_index, in_addr_t ip, macaddr_t o_mac) { 193 | if (!inited) { 194 | return HAL_ERR_CALLED_BEFORE_INIT; 195 | } 196 | if (if_index >= N_IFACE_ON_BOARD || if_index < 0) { 197 | return HAL_ERR_INVALID_PARAMETER; 198 | } 199 | 200 | if ((ip & 0xe0) == 0xe0) { 201 | uint8_t multicasting_mac[6] = {0x01, 0, 0x5e, (uint8_t)((ip >> 8) & 0x7f), (uint8_t)(ip >> 16), (uint8_t)(ip >> 24)}; 202 | memcpy(o_mac, multicasting_mac, sizeof(macaddr_t)); 203 | return 0; 204 | } 205 | 206 | for (int i = 0; i < ARP_TABLE_SIZE; i++) { 207 | if (arpTable[i].if_index == if_index && arpTable[i].ip == ip) { 208 | memcpy(o_mac, arpTable[i].mac, sizeof(macaddr_t)); 209 | return 0; 210 | } 211 | } 212 | 213 | if (debugEnabled) { 214 | xil_printf( 215 | "HAL_ArpGetMacAddress: asking for ip address with arp request\r\n"); 216 | } 217 | // request 218 | XAxiDma_Bd *bd; 219 | WaitTxBdAvailable(); 220 | XAxiDma_BdRingAlloc(txRing, 1, &bd); 221 | txBufferUsed++; 222 | 223 | UINTPTR addr = XAxiDma_BdGetBufAddr(bd); 224 | XAxiDma_BdClear(bd); 225 | XAxiDma_BdSetBufAddr(bd, addr); 226 | XAxiDma_BdSetLength(bd, IP_OFFSET + ARP_LENGTH, txRing->MaxTransferLen); 227 | XAxiDma_BdSetCtrl(bd, 228 | XAXIDMA_BD_CTRL_TXSOF_MASK | XAXIDMA_BD_CTRL_TXEOF_MASK); 229 | 230 | u8 *buffer = (u8 *)addr; 231 | // dst mac 232 | for (int i = 0; i < 6; i++) { 233 | buffer[i] = 0xff; 234 | } 235 | // src mac 236 | memcpy(&buffer[6], interface_mac, sizeof(macaddr_t)); 237 | // VLAN 238 | buffer[12] = 0x81; 239 | buffer[13] = 0x00; 240 | // PID 241 | buffer[14] = 0x00; 242 | buffer[15] = if_index + 1; 243 | // ARP 244 | buffer[16] = 0x08; 245 | buffer[17] = 0x06; 246 | // hardware type 247 | buffer[18] = 0x00; 248 | buffer[19] = 0x01; 249 | // protocol type 250 | buffer[20] = 0x08; 251 | buffer[21] = 0x00; 252 | // hardware size 253 | buffer[22] = 0x06; 254 | // protocol size 255 | buffer[23] = 0x04; 256 | // opcode 257 | buffer[24] = 0x00; 258 | buffer[25] = 0x01; 259 | // sender 260 | memcpy(&buffer[26], interface_mac, sizeof(macaddr_t)); 261 | memcpy(&buffer[32], &interface_addrs[if_index], sizeof(in_addr_t)); 262 | // target 263 | memset(&buffer[36], 0, sizeof(macaddr_t)); 264 | memcpy(&buffer[42], &ip, sizeof(in_addr_t)); 265 | 266 | XAxiDma_BdRingToHw(txRing, 1, bd); 267 | return HAL_ERR_IP_NOT_EXIST; 268 | } 269 | 270 | int HAL_GetInterfaceMacAddress(int if_index, macaddr_t o_mac) { 271 | if (!inited) { 272 | return HAL_ERR_CALLED_BEFORE_INIT; 273 | } 274 | if (if_index >= N_IFACE_ON_BOARD || if_index < 0) { 275 | return HAL_ERR_IFACE_NOT_EXIST; 276 | } 277 | 278 | memcpy(o_mac, interface_mac, sizeof(macaddr_t)); 279 | return 0; 280 | } 281 | 282 | int HAL_ReceiveIPPacket(int if_index_mask, uint8_t *buffer, size_t length, 283 | macaddr_t src_mac, macaddr_t dst_mac, int64_t timeout, 284 | int *if_index) { 285 | if (!inited) { 286 | return HAL_ERR_CALLED_BEFORE_INIT; 287 | } 288 | if ((if_index_mask & ((1 << N_IFACE_ON_BOARD) - 1)) == 0 || (timeout < 0 && timeout != -1)) { 289 | return HAL_ERR_INVALID_PARAMETER; 290 | } 291 | if (if_index_mask != ((1 << N_IFACE_ON_BOARD) - 1)) { 292 | return HAL_ERR_NOT_SUPPORTED; 293 | } 294 | XAxiDma_Bd *bd; 295 | uint64_t begin = HAL_GetTicks(); 296 | uint64_t current_time = 0; 297 | while ((current_time = HAL_GetTicks()) < begin + timeout || timeout == -1) { 298 | if (XAxiDma_BdRingFromHw(rxRing, 1, &bd) == 1) { 299 | // See AXI Ethernet Table 3-15 300 | u32 length = XAxiDma_BdRead(bd, XAXIDMA_BD_USR4_OFFSET) & 0xFFFF; 301 | u8 *data = (u8 *)XAxiDma_BdGetBufAddr(bd); 302 | if (data && length >= IP_OFFSET && data[16] == 0x08 && data[17] == 0x00) { 303 | // IPv4 304 | memcpy(dst_mac, data, sizeof(macaddr_t)); 305 | memcpy(src_mac, &data[6], sizeof(macaddr_t)); 306 | // Vlan ID 1-4 307 | *if_index = data[15] - 1; 308 | 309 | size_t ip_len = length - IP_OFFSET; 310 | size_t real_length = length > ip_len ? ip_len : length; 311 | memcpy(buffer, &data[IP_OFFSET], real_length); 312 | 313 | PutBackBd(bd); 314 | return real_length; 315 | } else if (data && length >= IP_OFFSET + ARP_LENGTH && data[16] == 0x08 && 316 | data[17] == 0x06) { 317 | // ARP 318 | macaddr_t mac; 319 | memcpy(mac, &data[26], sizeof(macaddr_t)); 320 | in_addr_t ip; 321 | memcpy(&ip, &data[32], sizeof(in_addr_t)); 322 | u32 vlan = data[15] - 1; 323 | 324 | // update ARP Table 325 | int insert = 1; 326 | for (int i = 0; i < ARP_TABLE_SIZE; i++) { 327 | if (arpTable[i].if_index == vlan && 328 | memcmp(arpTable[i].mac, mac, sizeof(macaddr_t)) == 0) { 329 | arpTable[i].ip = ip; 330 | insert = 0; 331 | break; 332 | } 333 | } 334 | 335 | if (insert) { 336 | memmove(&arpTable[1], arpTable, 337 | (ARP_TABLE_SIZE - 1) * sizeof(struct ArpTableEntry)); 338 | arpTable[0].if_index = vlan; 339 | memcpy(arpTable[0].mac, mac, sizeof(macaddr_t)); 340 | arpTable[0].ip = ip; 341 | if (debugEnabled) { 342 | xil_printf("HAL_ReceiveIPPacket: learned ARP from %d.%d.%d.%d\r\n", 343 | ip & 0xFF, (ip >> 8) & 0xFF, (ip >> 16) & 0xFF, 344 | ip >> 24); 345 | } 346 | } 347 | 348 | in_addr_t dst_ip; 349 | memcpy(&dst_ip, &data[42], sizeof(in_addr_t)); 350 | if (vlan < N_IFACE_ON_BOARD && dst_ip == interface_addrs[vlan] && data[25] == 0x01) { 351 | // reply 352 | XAxiDma_Bd *bd; 353 | WaitTxBdAvailable(); 354 | XAxiDma_BdRingAlloc(txRing, 1, &bd); 355 | txBufferUsed++; 356 | 357 | UINTPTR addr = XAxiDma_BdGetBufAddr(bd); 358 | XAxiDma_BdClear(bd); 359 | XAxiDma_BdSetBufAddr(bd, addr); 360 | XAxiDma_BdSetLength(bd, IP_OFFSET + ARP_LENGTH, 361 | txRing->MaxTransferLen); 362 | XAxiDma_BdSetCtrl(bd, XAXIDMA_BD_CTRL_TXSOF_MASK | 363 | XAXIDMA_BD_CTRL_TXEOF_MASK); 364 | 365 | u8 *buffer = (u8 *)addr; 366 | memcpy(buffer, &data[6], sizeof(macaddr_t)); 367 | memcpy(&buffer[6], interface_mac, sizeof(macaddr_t)); 368 | // VLAN 369 | buffer[12] = 0x81; 370 | buffer[13] = 0x00; 371 | // PID 372 | buffer[14] = 0x00; 373 | buffer[15] = vlan + 1; 374 | // ARP 375 | buffer[16] = 0x08; 376 | buffer[17] = 0x06; 377 | // hardware type 378 | buffer[18] = 0x00; 379 | buffer[19] = 0x01; 380 | // protocol type 381 | buffer[20] = 0x08; 382 | buffer[21] = 0x00; 383 | // hardware size 384 | buffer[22] = 0x06; 385 | // protocol size 386 | buffer[23] = 0x04; 387 | // opcode 388 | buffer[24] = 0x00; 389 | buffer[25] = 0x02; 390 | // sender 391 | memcpy(&buffer[26], interface_mac, sizeof(macaddr_t)); 392 | memcpy(&buffer[32], &dst_ip, sizeof(in_addr_t)); 393 | // target 394 | memcpy(&buffer[36], &data[26], sizeof(macaddr_t)); 395 | memcpy(&buffer[42], &data[32], sizeof(in_addr_t)); 396 | 397 | XAxiDma_BdRingToHw(txRing, 1, bd); 398 | 399 | if (debugEnabled) { 400 | xil_printf("HAL_ReceiveIPPacket: replied ARP to %d.%d.%d.%d\r\n", 401 | ip & 0xFF, (ip >> 8) & 0xFF, (ip >> 16) & 0xFF, 402 | ip >> 24); 403 | } 404 | } 405 | } else { 406 | if (debugEnabled) { 407 | xil_printf("HAL_ReceiveIPPacket: ignore unrecognized packet\r\n"); 408 | } 409 | } 410 | PutBackBd(bd); 411 | } 412 | } 413 | return 0; 414 | } 415 | 416 | int HAL_SendIPPacket(int if_index, uint8_t *buffer, size_t length, 417 | macaddr_t dst_mac) { 418 | if (!inited) { 419 | return HAL_ERR_CALLED_BEFORE_INIT; 420 | } 421 | if (if_index >= N_IFACE_ON_BOARD || if_index < 0) { 422 | return HAL_ERR_INVALID_PARAMETER; 423 | } 424 | XAxiDma_Bd *bd; 425 | WaitTxBdAvailable(); 426 | XAxiDma_BdRingAlloc(txRing, 1, &bd); 427 | txBufferUsed++; 428 | 429 | UINTPTR addr = XAxiDma_BdGetBufAddr(bd); 430 | XAxiDma_BdClear(bd); 431 | XAxiDma_BdSetBufAddr(bd, addr); 432 | u8 *data = (u8 *)addr; 433 | memcpy(data, dst_mac, sizeof(macaddr_t)); 434 | memcpy(&data[6], interface_mac, sizeof(macaddr_t)); 435 | // VLAN 436 | data[12] = 0x81; 437 | data[13] = 0x00; 438 | // PID 439 | data[14] = 0x00; 440 | data[15] = if_index + 1; 441 | // IPv4 442 | data[16] = 0x08; 443 | data[17] = 0x00; 444 | memcpy(&data[IP_OFFSET], buffer, length); 445 | XAxiDma_BdSetLength(bd, length + IP_OFFSET, txRing->MaxTransferLen); 446 | XAxiDma_BdSetCtrl(bd, 447 | XAXIDMA_BD_CTRL_TXSOF_MASK | XAXIDMA_BD_CTRL_TXEOF_MASK); 448 | XAxiDma_BdRingToHw(txRing, 1, bd); 449 | return 0; 450 | } 451 | -------------------------------------------------------------------------------- /Homework/boilerplate/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | boilerplate 3 | std 4 | std.cpp 5 | !*_output*.out 6 | !Makefile 7 | -------------------------------------------------------------------------------- /Homework/boilerplate/Makefile: -------------------------------------------------------------------------------- 1 | CXX ?= g++ 2 | LAB_ROOT ?= ../.. 3 | BACKEND ?= LINUX 4 | CXXFLAGS ?= --std=c++11 -I $(LAB_ROOT)/HAL/include -DROUTER_BACKEND_$(BACKEND) 5 | LDFLAGS ?= -lpcap 6 | 7 | .PHONY: all clean 8 | all: boilerplate 9 | 10 | clean: 11 | rm -f *.o boilerplate std 12 | 13 | %.o: %.cpp 14 | $(CXX) $(CXXFLAGS) -c $^ -o $@ 15 | 16 | hal.o: $(LAB_ROOT)/HAL/src/linux/router_hal.cpp 17 | $(CXX) $(CXXFLAGS) -c $^ -o $@ 18 | 19 | boilerplate: main.o hal.o protocol.o checksum.o lookup.o forwarding.o 20 | $(CXX) $^ -o $@ $(LDFLAGS) 21 | -------------------------------------------------------------------------------- /Homework/boilerplate/checksum.cpp: -------------------------------------------------------------------------------- 1 | ../checksum/checksum.cpp -------------------------------------------------------------------------------- /Homework/boilerplate/forwarding.cpp: -------------------------------------------------------------------------------- 1 | ../forwarding/forwarding.cpp -------------------------------------------------------------------------------- /Homework/boilerplate/lookup.cpp: -------------------------------------------------------------------------------- 1 | ../lookup/lookup.cpp -------------------------------------------------------------------------------- /Homework/boilerplate/main.cpp: -------------------------------------------------------------------------------- 1 | #include "rip.h" 2 | #include "router.h" 3 | #include "router_hal.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | extern bool validateIPChecksum(uint8_t *packet, size_t len); 10 | extern void update(bool insert, RoutingTableEntry entry); 11 | extern bool query(uint32_t addr, uint32_t *nexthop, uint32_t *if_index); 12 | extern bool forward(uint8_t *packet, size_t len); 13 | extern bool disassemble(const uint8_t *packet, uint32_t len, RipPacket *output); 14 | extern uint32_t assemble(const RipPacket *rip, uint8_t *buffer); 15 | 16 | uint8_t packet[2048]; 17 | uint8_t output[2048]; 18 | // 0: 10.0.0.1 19 | // 1: 10.0.1.1 20 | // 2: 10.0.2.1 21 | // 3: 10.0.3.1 22 | // 你可以按需进行修改,注意端序 23 | in_addr_t addrs[N_IFACE_ON_BOARD] = {0x0100000a, 0x0101000a, 0x0102000a, 24 | 0x0103000a}; 25 | 26 | int main(int argc, char *argv[]) { 27 | // 0a. 28 | int res = HAL_Init(1, addrs); 29 | if (res < 0) { 30 | return res; 31 | } 32 | 33 | // 0b. Add direct routes 34 | // For example: 35 | // 10.0.0.0/24 if 0 36 | // 10.0.1.0/24 if 1 37 | // 10.0.2.0/24 if 2 38 | // 10.0.3.0/24 if 3 39 | for (uint32_t i = 0; i < N_IFACE_ON_BOARD; i++) { 40 | RoutingTableEntry entry = { 41 | .addr = addrs[i], // big endian 42 | .len = 24, // small endian 43 | .if_index = i, // small endian 44 | .nexthop = 0 // big endian, means direct 45 | }; 46 | update(true, entry); 47 | } 48 | 49 | uint64_t last_time = 0; 50 | while (1) { 51 | uint64_t time = HAL_GetTicks(); 52 | if (time > last_time + 30 * 1000) { 53 | // What to do? 54 | // send complete routing table to every interface 55 | // ref. RFC2453 3.8 56 | // multicast MAC for 224.0.0.9 is 01:00:5e:00:00:09 57 | printf("30s Timer\n"); 58 | last_time = time; 59 | } 60 | 61 | int mask = (1 << N_IFACE_ON_BOARD) - 1; 62 | macaddr_t src_mac; 63 | macaddr_t dst_mac; 64 | int if_index; 65 | res = HAL_ReceiveIPPacket(mask, packet, sizeof(packet), src_mac, dst_mac, 66 | 1000, &if_index); 67 | if (res == HAL_ERR_EOF) { 68 | break; 69 | } else if (res < 0) { 70 | return res; 71 | } else if (res == 0) { 72 | // Timeout 73 | continue; 74 | } else if (res > sizeof(packet)) { 75 | // packet is truncated, ignore it 76 | continue; 77 | } 78 | 79 | // 1. validate 80 | if (!validateIPChecksum(packet, res)) { 81 | printf("Invalid IP Checksum\n"); 82 | continue; 83 | } 84 | in_addr_t src_addr, dst_addr; 85 | // extract src_addr and dst_addr from packet 86 | // big endian 87 | 88 | // 2. check whether dst is me 89 | bool dst_is_me = false; 90 | for (int i = 0; i < N_IFACE_ON_BOARD; i++) { 91 | if (memcmp(&dst_addr, &addrs[i], sizeof(in_addr_t)) == 0) { 92 | dst_is_me = true; 93 | break; 94 | } 95 | } 96 | // TODO: Handle rip multicast address(224.0.0.9)? 97 | 98 | if (dst_is_me) { 99 | // 3a.1 100 | RipPacket rip; 101 | // check and validate 102 | if (disassemble(packet, res, &rip)) { 103 | if (rip.command == 1) { 104 | // 3a.3 request, ref. RFC2453 3.9.1 105 | // only need to respond to whole table requests in the lab 106 | RipPacket resp; 107 | // TODO: fill resp 108 | // assemble 109 | // IP 110 | output[0] = 0x45; 111 | // ... 112 | // UDP 113 | // port = 520 114 | output[20] = 0x02; 115 | output[21] = 0x08; 116 | // ... 117 | // RIP 118 | uint32_t rip_len = assemble(&resp, &output[20 + 8]); 119 | // checksum calculation for ip and udp 120 | // if you don't want to calculate udp checksum, set it to zero 121 | // send it back 122 | HAL_SendIPPacket(if_index, output, rip_len + 20 + 8, src_mac); 123 | } else { 124 | // 3a.2 response, ref. RFC2453 3.9.2 125 | // update routing table 126 | // new metric = ? 127 | // update metric, if_index, nexthop 128 | // what is missing from RoutingTableEntry? 129 | // TODO: use query and update 130 | // triggered updates? ref. RFC2453 3.10.1 131 | } 132 | } 133 | } else { 134 | // 3b.1 dst is not me 135 | // forward 136 | // beware of endianness 137 | uint32_t nexthop, dest_if; 138 | if (query(dst_addr, &nexthop, &dest_if)) { 139 | // found 140 | macaddr_t dest_mac; 141 | // direct routing 142 | if (nexthop == 0) { 143 | nexthop = dst_addr; 144 | } 145 | if (HAL_ArpGetMacAddress(dest_if, nexthop, dest_mac) == 0) { 146 | // found 147 | memcpy(output, packet, res); 148 | // update ttl and checksum 149 | forward(output, res); 150 | // TODO: you might want to check ttl=0 case 151 | HAL_SendIPPacket(dest_if, output, res, dest_mac); 152 | } else { 153 | // not found 154 | // you can drop it 155 | printf("ARP not found for %x\n", nexthop); 156 | } 157 | } else { 158 | // not found 159 | // optionally you can send ICMP Host Unreachable 160 | printf("IP not found for %x\n", src_addr); 161 | } 162 | } 163 | } 164 | return 0; 165 | } -------------------------------------------------------------------------------- /Homework/boilerplate/protocol.cpp: -------------------------------------------------------------------------------- 1 | ../protocol/protocol.cpp -------------------------------------------------------------------------------- /Homework/boilerplate/rip.h: -------------------------------------------------------------------------------- 1 | ../protocol/rip.h -------------------------------------------------------------------------------- /Homework/boilerplate/router.h: -------------------------------------------------------------------------------- 1 | ../lookup/router.h -------------------------------------------------------------------------------- /Homework/checksum/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | checksum 3 | std 4 | std.cpp 5 | !*_output*.out 6 | !Makefile 7 | -------------------------------------------------------------------------------- /Homework/checksum/Makefile: -------------------------------------------------------------------------------- 1 | CXX ?= g++ 2 | LAB_ROOT ?= ../.. 3 | BACKEND ?= STDIO 4 | CXXFLAGS ?= --std=c++11 -I $(LAB_ROOT)/HAL/include -DROUTER_BACKEND_$(BACKEND) 5 | LDFLAGS ?= -lpcap 6 | 7 | .PHONY: all clean grade 8 | all: checksum 9 | 10 | clean: 11 | rm -f *.o checksum std 12 | 13 | grade: checksum 14 | python3 grade.py 15 | 16 | %.o: %.cpp 17 | $(CXX) $(CXXFLAGS) -c $^ -o $@ 18 | 19 | hal.o: $(LAB_ROOT)/HAL/src/stdio/router_hal.cpp 20 | $(CXX) $(CXXFLAGS) -c $^ -o $@ 21 | 22 | checksum: checksum.o main.o hal.o 23 | $(CXX) $^ -o $@ $(LDFLAGS) 24 | 25 | std: std.o main.o hal.o 26 | $(CXX) $^ -o $@ $(LDFLAGS) 27 | -------------------------------------------------------------------------------- /Homework/checksum/checksum.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using u8 = uint8_t; 6 | using u16 = uint16_t; 7 | using u32 = uint32_t; 8 | 9 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 10 | #define BE16(x) __builtin_bswap16(x) 11 | #define BE32(x) __builtin_bswap32(x) 12 | #else 13 | #define BE16(x) x 14 | #define BE32(x) x 15 | #endif 16 | 17 | struct iphdr { 18 | u8 ihl : 4, version : 4; 19 | u8 tos; 20 | u16 tot_len; 21 | u16 id; 22 | u16 frag_off; 23 | u8 ttl; 24 | u8 protocol; 25 | u16 check; 26 | u32 saddr; 27 | u32 daddr; 28 | }; 29 | 30 | u16 calc_check_sum(u8 *packet) { 31 | iphdr *hdr = (iphdr *)packet; 32 | u16 old = hdr->check; 33 | hdr->check = 0; 34 | u32 sum = 0; 35 | for (u16 *p = (u16 *)packet, *end = p + hdr->ihl * 2; p < end; ++p) { 36 | sum += BE16(*p); 37 | } 38 | hdr->check = old; 39 | sum = (sum & 0xFFFF) + (sum >> 16); 40 | sum = (sum & 0xFFFF) + (sum >> 16); 41 | return ~sum; 42 | } 43 | 44 | /** 45 | * @brief 进行 IP 头的校验和的验证 46 | * @param packet 完整的 IP 头和载荷 47 | * @param len 即 packet 的长度,单位是字节,保证包含完整的 IP 头 48 | * @return 校验和无误则返回 true ,有误则返回 false 49 | */ 50 | bool validateIPChecksum(uint8_t *packet, size_t len) { return calc_check_sum(packet) == BE16(((iphdr *)packet)->check); } -------------------------------------------------------------------------------- /Homework/checksum/data/checksum_input1.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MashPlant/Router-Lab/d98900c038bc9b892acb430da125f460d8857760/Homework/checksum/data/checksum_input1.pcap -------------------------------------------------------------------------------- /Homework/checksum/data/checksum_input2.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MashPlant/Router-Lab/d98900c038bc9b892acb430da125f460d8857760/Homework/checksum/data/checksum_input2.pcap -------------------------------------------------------------------------------- /Homework/checksum/data/checksum_input3.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MashPlant/Router-Lab/d98900c038bc9b892acb430da125f460d8857760/Homework/checksum/data/checksum_input3.pcap -------------------------------------------------------------------------------- /Homework/checksum/data/checksum_input4.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MashPlant/Router-Lab/d98900c038bc9b892acb430da125f460d8857760/Homework/checksum/data/checksum_input4.pcap -------------------------------------------------------------------------------- /Homework/checksum/data/checksum_output1.out: -------------------------------------------------------------------------------- 1 | Yes 2 | Yes 3 | Yes 4 | Yes 5 | Yes 6 | Yes 7 | Yes 8 | Yes 9 | Yes 10 | Yes 11 | -------------------------------------------------------------------------------- /Homework/checksum/data/checksum_output2.out: -------------------------------------------------------------------------------- 1 | No 2 | No 3 | Yes 4 | No 5 | Yes 6 | No 7 | Yes 8 | No 9 | No 10 | Yes 11 | -------------------------------------------------------------------------------- /Homework/checksum/data/checksum_output3.out: -------------------------------------------------------------------------------- 1 | Yes 2 | No 3 | Yes 4 | No 5 | No 6 | No 7 | No 8 | No 9 | Yes 10 | No 11 | -------------------------------------------------------------------------------- /Homework/checksum/data/checksum_output4.out: -------------------------------------------------------------------------------- 1 | Yes 2 | -------------------------------------------------------------------------------- /Homework/checksum/grade.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import re 5 | import sys 6 | import os 7 | import json 8 | import subprocess 9 | import time 10 | from os.path import isfile, join 11 | import random 12 | import string 13 | import signal 14 | import glob 15 | import traceback 16 | 17 | prefix = 'checksum' 18 | exe = prefix 19 | if len(sys.argv) > 1: 20 | exe = sys.argv[1] 21 | 22 | try: 23 | import pyshark 24 | except Exception: 25 | print('Install pyshark (pip3 install pyshark) first!') 26 | sys.exit(1) 27 | 28 | def write_grade(grade, total): 29 | data = {} 30 | data['grade'] = grade 31 | if os.isatty(1): 32 | print('Passed: {}/{}'.format(grade, total)) 33 | else: 34 | print(json.dumps(data)) 35 | 36 | sys.exit(0) 37 | 38 | 39 | if __name__ == '__main__': 40 | 41 | if sys.version_info[0] != 3: 42 | print("Plz use python3") 43 | sys.exit() 44 | 45 | if os.isatty(1): 46 | print('Removing all output files') 47 | os.system('rm -f data/{}user*.out'.format(prefix)) 48 | 49 | total = len(glob.glob("data/{}_input*.pcap".format(prefix))) 50 | 51 | grade = 0 52 | 53 | for i in range(1, total+1): 54 | in_file = "data/{}_input{}.pcap".format(prefix, i) 55 | out_file = "data/{}_user{}.out".format(prefix, i) 56 | ans_file = "data/{}_output{}.out".format(prefix, i) 57 | 58 | if os.isatty(1): 59 | print('Running \'./{} < {} > {}\''.format(exe, in_file, out_file)) 60 | p = subprocess.Popen(['./{}'.format(exe)], stdout=open(out_file, 'w'), stdin=open(in_file, 'r')) 61 | start_time = time.time() 62 | 63 | while p.poll() is None: 64 | if time.time() - start_time > 1: 65 | p.kill() 66 | 67 | try: 68 | out = [line.strip() for line in open(out_file, 'r').readlines() if line.strip()] 69 | ans = [line.strip() for line in open(ans_file, 'r').readlines() if line.strip()] 70 | 71 | if out == ans: 72 | grade += 1 73 | elif os.isatty(1): 74 | limit = 1 75 | count = 0 76 | reader = pyshark.FileCapture(in_file) 77 | packets = list(reader) 78 | print('Wrong Answer (showing only first {} packets):'.format(limit)) 79 | for i in range(len(ans)): 80 | if i >= len(out) or out[i] != ans[i]: 81 | count += 1 82 | print('Answer is wrong for packet #{}: {}'.format(i, packets[i]['ip'])) 83 | if count == limit: 84 | break 85 | print('Diff: ') 86 | os.system('diff -u {} {} | head -n 10'.format(out_file, ans_file)) 87 | reader.close() 88 | except Exception: 89 | if os.isatty(1): 90 | print('Unexpected exception caught:') 91 | traceback.print_exc() 92 | 93 | write_grade(grade, total) 94 | 95 | -------------------------------------------------------------------------------- /Homework/checksum/main.cpp: -------------------------------------------------------------------------------- 1 | #include "router_hal.h" 2 | #include 3 | #include 4 | #include 5 | 6 | extern bool validateIPChecksum(uint8_t *packet, size_t len); 7 | 8 | in_addr_t addrs[N_IFACE_ON_BOARD] = {0}; 9 | uint8_t packet[1024]; 10 | 11 | int main(int argc, char *argv[]) { 12 | int res = HAL_Init(0, addrs); 13 | if (res < 0) { 14 | return res; 15 | } 16 | while (1) { 17 | int mask = (1 << N_IFACE_ON_BOARD) - 1; 18 | macaddr_t src_mac; 19 | macaddr_t dst_mac; 20 | int if_index; 21 | res = HAL_ReceiveIPPacket(mask, packet, sizeof(packet), src_mac, 22 | dst_mac, -1, &if_index); 23 | if (res == HAL_ERR_EOF) { 24 | break; 25 | } else if (res < 0) { 26 | return res; 27 | } 28 | printf("%s\n", validateIPChecksum(packet, res) ? "Yes" : "No"); 29 | } 30 | return 0; 31 | } -------------------------------------------------------------------------------- /Homework/forwarding/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | forwarding 3 | std 4 | std.cpp 5 | !*_output*.out 6 | !Makefile 7 | -------------------------------------------------------------------------------- /Homework/forwarding/Makefile: -------------------------------------------------------------------------------- 1 | CXX ?= g++ 2 | LAB_ROOT ?= ../.. 3 | BACKEND ?= STDIO 4 | CXXFLAGS ?= --std=c++11 -I $(LAB_ROOT)/HAL/include -DROUTER_BACKEND_$(BACKEND) 5 | LDFLAGS ?= -lpcap 6 | 7 | .PHONY: all clean grade 8 | all: forwarding 9 | 10 | clean: 11 | rm -f *.o forwarding std 12 | 13 | grade: forwarding 14 | python3 grade.py 15 | 16 | %.o: %.cpp 17 | $(CXX) $(CXXFLAGS) -c $^ -o $@ 18 | 19 | hal.o: $(LAB_ROOT)/HAL/src/stdio/router_hal.cpp 20 | $(CXX) $(CXXFLAGS) -c $^ -o $@ 21 | 22 | forwarding: forwarding.o main.o hal.o 23 | $(CXX) $^ -o $@ $(LDFLAGS) 24 | 25 | std: std.o main.o hal.o 26 | $(CXX) $^ -o $@ $(LDFLAGS) 27 | -------------------------------------------------------------------------------- /Homework/forwarding/data/forwarding_input1.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MashPlant/Router-Lab/d98900c038bc9b892acb430da125f460d8857760/Homework/forwarding/data/forwarding_input1.pcap -------------------------------------------------------------------------------- /Homework/forwarding/data/forwarding_input2.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MashPlant/Router-Lab/d98900c038bc9b892acb430da125f460d8857760/Homework/forwarding/data/forwarding_input2.pcap -------------------------------------------------------------------------------- /Homework/forwarding/data/forwarding_input3.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MashPlant/Router-Lab/d98900c038bc9b892acb430da125f460d8857760/Homework/forwarding/data/forwarding_input3.pcap -------------------------------------------------------------------------------- /Homework/forwarding/data/forwarding_input4.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MashPlant/Router-Lab/d98900c038bc9b892acb430da125f460d8857760/Homework/forwarding/data/forwarding_input4.pcap -------------------------------------------------------------------------------- /Homework/forwarding/data/forwarding_output1.out: -------------------------------------------------------------------------------- 1 | 45000020000040003f110e63b7ad71b701020304e36e2766000c635a3132330a 2 | 45000020000040003f110e63b7ad71b701020304e36e2766000c635a3132330a0482d1 3 | 45000020000040003f110e63b7ad71b701020304e36e2766000c635a3132330a0f8dbcb121f4183fdd 4 | 45000020000040003f110e63b7ad71b701020304e36e2766000c635a3132330a9b78fb 5 | 45000020000040003f110e63b7ad71b701020304e36e2766000c635a3132330a3c2cdcdd1a210062 6 | 45000020000040003f110e63b7ad71b701020304e36e2766000c635a3132330a69972766 7 | 45000020000040003f110e63b7ad71b701020304e36e2766000c635a3132330a2f5e78cf2c 8 | 45000020000040003f110e63b7ad71b701020304e36e2766000c635a3132330ab311a66cd7d4 9 | 45000020000040003f110e63b7ad71b701020304e36e2766000c635a3132330a87 10 | 45000020000040003f110e63b7ad71b701020304e36e2766000c635a3132330a 11 | -------------------------------------------------------------------------------- /Homework/forwarding/data/forwarding_output2.out: -------------------------------------------------------------------------------- 1 | 45000020000040003f110e63b7ad71b701020304e36e2766000c635a3132330aeb779a 2 | 45000020000040003f110e63b7ad71b701020304e36e2766000c635a3132330af87ee5abc878438403 3 | 45000020000040003f110e63b7ad71b701020304e36e2766000c635a3132330a 4 | 45000020000040003f110e63b7ad71b701020304e36e2766000c635a3132330ab2c89fa0b32b34ed 5 | -------------------------------------------------------------------------------- /Homework/forwarding/data/forwarding_output3.out: -------------------------------------------------------------------------------- 1 | 45000020000040003f110e63b7ad71b701020304e36e2766000c635a3132330ab293caefc36639371802ca0e509dc074ba2f05d283944001d76b0498350d611fe4e4f3f68fd3ebd0587d325c867aa88f5c1ca7be092e0290b3abbf587759a4a257e47edfdc912a807944326d43de609a1394385001d2b184c2551a49f98bd3b16c0b75b2f66821125b5b1f2e95bf777b744e84768f756317d499f3d698df1dee6e641ca816e9155ace04e7c565b3a98da7313b7576130f59f7525c33ef4b3d35d40e09d21642a8b92b05e285537cccaca201955c3ef5f247aac9d58aec8788435b089d6f57a1b78b10ff5188ad2a18f7ffee912e664919495c65ae808f1dab7d777927dd5ca7f1960c5f70de0bd5f266dfeacba0477046a03d76337cb8ad4f90245c952eecc1fd97f720c39ae87dea6374588ebf2cc4386db1e23c964136acc6e8b9b6f3588c81bdc0b06d3f109a19d9ab51b142b0269d89b4a4f58bd9ea07a73c98ec27df97540aba8a7183925b1775737986c72c62574094ff3e42131d7ab28cfa547cc04798c45792a97329e9fe9c9fddb50f4a4f31e60897c204d0c2084abea8ec969b071fa935363b06a6e6 2 | 45000020000040003f110e63b7ad71b701020304e36e2766000c635a3132330a77e4daa2b07889fa8e249303b9f3444c9d5966308f52f8ea66884ee0d74f980dd6941ae42806522ff1ef6b13720ea5545e0a25e90eca6784ae9d483d08a72ff850be906d1559250b187116e0649a6502f118cd8711691022cd0f8a9bd60e3560bafb0e5cfc47f6ae74a89601bfbf78fd7698bdda622ea00004f7ef86e5d17bcde4d50d576515b13a56711700f1d6c39eb14fdecaa1f1d7f68d53ea7a6231a8397ceb7b962770e96f1039f2bfbf68ead1ef3ddc0fb5f31d88e3e5c66216276bf2beece51cddb3a43516a6573ee817ba4afaa6c5c38d6c04bcb62bc8278155c7383de26bc1d28fbe3785f253956d8575d84295d9e36c4b22df0484402264c20b5ed3728c74dd4007eeb0b4c345382aa724317b27c231908713ec4ddc07328f84e5cbb7e78e3cb8f52fc37ef43c0fd5e4804b7fcd5c1834cc4551027fb2abb24ccd49fba440e5300e1b3617efc31bd931151dffa94d1baaf2b0c5fddba303cee2c638e083aa34667081c03cdd08eedc12d33e5cd06cc593e3d42820e9e104887804682c963c2c2fcd9e0af1f627cca25fd42486e9756fe3378822de2c03916d499ad49b0a9b6b1aff8ba54a2b08c09594919bed776e503a3f0a1c48bfbba708c4786eca219110c2e41d9889a30829e0f1011f964e03ac8b6e1090d0f53a766625269bdb86f3b57ac0badf90d9c316ba0e5aa726b869ca3faaf8e293f59d5aaeadfd48acaa67ec34b63ac66e444874bc4b15c0b0f759329c4c8d91baf26833ffa3bd58f732b4e1db8740a4787d85fd594b2af697304b817f440353156348c9e713414d72f70537fdcf0601b4d24fa1683c2c0c6628a96c6f85b77172ff4d53b1cf7fad95da37971b3af1f019f50c716f211c5325 3 | 45000020000040003f110e63b7ad71b701020304e36e2766000c635a3132330a731656f02808b6a7503de668e431153548f4aef563f16f5109b55cdb14cde037f1d0cfe6f8b9ea4a72e69bf5287638b17c655446e88945c72140bc0ac8ba360d7e6a193564de8a67cb8da3b31889ca262efd4125b9387ce962997c294ab7d71469b7ba8b68e568914525ad9d47239fafde019157bded20f8ea5105b50687ae2a3da701797c136eecc01bd13c84c18ee03190ee25a965ddc8aa0946fe75e810c036ffce53bfa6ff2679d3b956f6b90fa26d42c904bf52642d1107d9538b879ed0573f2df3982817b711c58c9f8f402dc2e331700eaeb2f7978384aa60b8d178d57900f83b56c12622ec57d9fee3336f645d5c67391dd83f68eaed7c8031d56d06cbcab71b97b6222a75e5a08b783948b8e3095a43c078d8d860a39aef83260cf8c24ca976acd59ee30a94ea7b196a4a9c90187ea32dc3c5eb3a80e303c7404d966a52b83970e461166f76c403a1da607202e7fedb5ad7521065345b8b59b17c38fc3bc3ca926ef01657907c3c5c09e2ec1144594cd4a5eea15e09f80e16a028a007a192506f741990350eafb1f683ad2572aca0226a04f23999085da28e0d3f99faf4c0f1d0afaa7aeca71f7119e41ec2c29c171befb8978522d10abd530c43eedf41ba1e80350ed990a6c9ba8d4706ed45a3405612231620b58c96c803cec671d87edf33289c3fe1641614f1b219c77e2f466591ff71a4de06e02456266b858bcd0379bed7c71387abd861afd01e07594ce9c4b88e17792de554be7c3796cce22b87c68a4885e190150ed10d16212e3bce45c09ce51260f3f6d51d23d39ec25f010b196c12c40d23e52ef8373fec74a1673cd38c0eaf1ed75cd712d9a17c65e96358e5f948f63a1fe4087a8a0daf2d46ae7988c8fa6a8cddcc24209d13210efb70b05560e4aa94cb755f243e742a30e588a97011735bd1894eebf5d4334971394b476f5c1b485ad15d9ee85b88b2dfe88e0feb3852a4bc8a1c99e50ff87d946d3048866731df5a09faeb18f838530c7e9ddc4e84f567053f47a57fe9d0960517921959e79f8e2c6a62487d236d171071682329b6b14bef2d579102f2fc1860d60df35fab82c227cc7e2720031a3fa75dc1df33aa39733a5c637a5abb62ad05f3293bea2aa952e68156b1b62bb4d8b7a013c2879cc08d9ff2b1b8d0b530aacfda0c8a984869585c99f7197cf23a0c82cc -------------------------------------------------------------------------------- /Homework/forwarding/data/forwarding_output4.out: -------------------------------------------------------------------------------- 1 | 46c00020c61640003f02000000000000e0000001940400001164ee9b000000003a93c1555d80a4c148 2 | -------------------------------------------------------------------------------- /Homework/forwarding/forwarding.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using u8 = uint8_t; 6 | using u16 = uint16_t; 7 | using u32 = uint32_t; 8 | 9 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 10 | #define BE16(x) __builtin_bswap16(x) 11 | #define BE32(x) __builtin_bswap32(x) 12 | #else 13 | #define BE16(x) x 14 | #define BE32(x) x 15 | #endif 16 | 17 | struct iphdr { 18 | u8 ihl : 4, version : 4; 19 | u8 tos; 20 | u16 tot_len; 21 | u16 id; 22 | u16 frag_off; 23 | u8 ttl; 24 | u8 protocol; 25 | u16 check; 26 | u32 saddr; 27 | u32 daddr; 28 | }; 29 | 30 | u16 calc_check_sum(u8 *packet) { 31 | iphdr *hdr = (iphdr *)packet; 32 | u16 old = hdr->check; 33 | hdr->check = 0; 34 | u32 sum = 0; 35 | for (u16 *p = (u16 *)packet, *end = p + hdr->ihl * 2; p < end; ++p) { 36 | sum += BE16(*p); 37 | } 38 | hdr->check = old; 39 | sum = (sum & 0xFFFF) + (sum >> 16); 40 | sum = (sum & 0xFFFF) + (sum >> 16); 41 | return ~sum; 42 | } 43 | 44 | /** 45 | * @brief 进行转发时所需的 IP 头的更新: 46 | * 你需要先检查 IP 头校验和的正确性,如果不正确,直接返回 false ; 47 | * 如果正确,请更新 TTL 和 IP 头校验和,并返回 true 。 48 | * 你可以从 checksum 题中复制代码到这里使用。 49 | * @param packet 收到的 IP 包,既是输入也是输出,原地更改 50 | * @param len 即 packet 的长度,单位为字节 51 | * @return 校验和无误则返回 true ,有误则返回 false 52 | */ 53 | bool forward(uint8_t *packet, size_t len) { 54 | // 在这里你不需要考虑 TTL 为 0 的情况,在最终你的路由器实现中才做要求 55 | u16 old = BE16(((iphdr *)packet)->check); 56 | if (calc_check_sum(packet) != old) { 57 | return false; 58 | } 59 | iphdr *hdr = (iphdr *)packet; 60 | --hdr->ttl; 61 | u32 sum = old + 0x100; 62 | sum = (sum & 0xFFFF) + (sum >> 16); 63 | hdr->check = BE16((u16) (sum == 0xFFFF ? 0 : sum)); 64 | return true; 65 | } -------------------------------------------------------------------------------- /Homework/forwarding/grade.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import re 5 | import sys 6 | import os 7 | import json 8 | import subprocess 9 | import time 10 | from os.path import isfile, join 11 | import random 12 | import string 13 | import signal 14 | import glob 15 | import traceback 16 | 17 | prefix = 'forwarding' 18 | exe = prefix 19 | if len(sys.argv) > 1: 20 | exe = sys.argv[1] 21 | 22 | try: 23 | import pyshark 24 | except Exception: 25 | print('Install pyshark (pip3 install pyshark) first!') 26 | sys.exit(1) 27 | 28 | def write_grade(grade, total): 29 | data = {} 30 | data['grade'] = grade 31 | if os.isatty(1): 32 | print('Passed: {}/{}'.format(grade, total)) 33 | else: 34 | print(json.dumps(data)) 35 | 36 | sys.exit(0) 37 | 38 | 39 | if __name__ == '__main__': 40 | 41 | if sys.version_info[0] != 3: 42 | print("Plz use python3") 43 | sys.exit() 44 | 45 | if os.isatty(1): 46 | print('Removing all output files') 47 | os.system('rm -f data/{}user*.out'.format(prefix)) 48 | 49 | total = len(glob.glob("data/{}_input*.pcap".format(prefix))) 50 | 51 | grade = 0 52 | 53 | for i in range(1, total+1): 54 | in_file = "data/{}_input{}.pcap".format(prefix, i) 55 | out_file = "data/{}_user{}.out".format(prefix, i) 56 | ans_file = "data/{}_output{}.out".format(prefix, i) 57 | 58 | if os.isatty(1): 59 | print('Running \'./{} < {} > {}\''.format(exe, in_file, out_file)) 60 | p = subprocess.Popen(['./{}'.format(exe)], stdout=open(out_file, 'w'), stdin=open(in_file, 'r')) 61 | start_time = time.time() 62 | 63 | while p.poll() is None: 64 | if time.time() - start_time > 1: 65 | p.kill() 66 | 67 | try: 68 | out = [line.strip() for line in open(out_file, 'r').readlines() if line.strip()] 69 | ans = [line.strip() for line in open(ans_file, 'r').readlines() if line.strip()] 70 | 71 | if out == ans: 72 | grade += 1 73 | elif os.isatty(1): 74 | limit = 1 75 | count = 0 76 | reader = pyshark.FileCapture(in_file) 77 | packets = list(reader) 78 | print('Wrong Answer (showing only first {} packets):'.format(limit)) 79 | for i in range(len(ans)): 80 | if i >= len(out) or out[i] != ans[i]: 81 | count += 1 82 | print('Answer is wrong for packet #{}: {}'.format(i, packets[i]['ip'])) 83 | if count == limit: 84 | break 85 | print('Diff: ') 86 | os.system('diff -u {} {} | head -n 10'.format(out_file, ans_file)) 87 | reader.close() 88 | except Exception: 89 | if os.isatty(1): 90 | print('Unexpected exception caught:') 91 | traceback.print_exc() 92 | 93 | write_grade(grade, total) 94 | 95 | -------------------------------------------------------------------------------- /Homework/forwarding/main.cpp: -------------------------------------------------------------------------------- 1 | #include "router_hal.h" 2 | #include 3 | #include 4 | #include 5 | 6 | extern bool forward(uint8_t *packet, size_t len); 7 | 8 | in_addr_t addrs[N_IFACE_ON_BOARD] = {0}; 9 | uint8_t packet[1024]; 10 | 11 | int main(int argc, char *argv[]) { 12 | int res = HAL_Init(0, addrs); 13 | if (res < 0) { 14 | return res; 15 | } 16 | while (1) { 17 | int mask = (1 << N_IFACE_ON_BOARD) - 1; 18 | macaddr_t src_mac; 19 | macaddr_t dst_mac; 20 | int if_index; 21 | res = HAL_ReceiveIPPacket(mask, packet, sizeof(packet), src_mac, 22 | dst_mac, -1, &if_index); 23 | if (res == HAL_ERR_EOF) { 24 | break; 25 | } else if (res < 0) { 26 | return res; 27 | } 28 | if (forward(packet, res)) { 29 | for (size_t i = 0; i < res;i++) { 30 | printf("%02x", packet[i]); 31 | } 32 | printf("\n"); 33 | } 34 | } 35 | return 0; 36 | } -------------------------------------------------------------------------------- /Homework/lookup/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | lookup 3 | std 4 | std.cpp 5 | !*_output*.out 6 | !Makefile 7 | -------------------------------------------------------------------------------- /Homework/lookup/Makefile: -------------------------------------------------------------------------------- 1 | CXX ?= g++ 2 | LAB_ROOT ?= ../.. 3 | BACKEND ?= STDIO 4 | CXXFLAGS ?= --std=c++11 -I $(LAB_ROOT)/HAL/include -DROUTER_BACKEND_$(BACKEND) 5 | LDFLAGS ?= -lpcap 6 | 7 | .PHONY: all clean grade 8 | all: lookup 9 | 10 | clean: 11 | rm -f *.o lookup std 12 | 13 | grade: lookup 14 | python3 grade.py 15 | 16 | %.o: %.cpp 17 | $(CXX) $(CXXFLAGS) -c $^ -o $@ 18 | 19 | hal.o: $(LAB_ROOT)/HAL/src/stdio/router_hal.cpp 20 | $(CXX) $(CXXFLAGS) -c $^ -o $@ 21 | 22 | lookup: lookup.o main.o hal.o 23 | $(CXX) $^ -o $@ $(LDFLAGS) 24 | 25 | std: std.o main.o hal.o 26 | $(CXX) $^ -o $@ $(LDFLAGS) 27 | -------------------------------------------------------------------------------- /Homework/lookup/data/lookup_input1.in: -------------------------------------------------------------------------------- 1 | I,0x00030201,24,9,0x0203a8c0 2 | I,0x04030201,32,10,0x0109a8c0 3 | Q,0x04030201 -------------------------------------------------------------------------------- /Homework/lookup/data/lookup_input2.in: -------------------------------------------------------------------------------- 1 | I,0x00030201,24,9,0x0203a8c0 2 | I,0x04030201,32,10,0x0109a8c0 3 | Q,0x01030201 4 | Q,0x02030201 5 | Q,0x03030201 6 | Q,0x04030201 7 | Q,0x05030201 -------------------------------------------------------------------------------- /Homework/lookup/data/lookup_input3.in: -------------------------------------------------------------------------------- 1 | I,0x00030201,24,9,0x0203a8c0 2 | I,0x04030201,32,10,0x0109a8c0 3 | Q,0x04030201 4 | Q,0x01030201 5 | Q,0x00000000 -------------------------------------------------------------------------------- /Homework/lookup/data/lookup_input4.in: -------------------------------------------------------------------------------- 1 | I,0x00030201,24,9,0x0203a8c0 2 | I,0x04030201,32,10,0x0109a8c0 3 | Q,0x04030201 4 | Q,0x01030201 5 | Q,0x00000000 6 | D,0x04030201,32 7 | Q,0x04030201 8 | Q,0x01030201 9 | Q,0x00000000 10 | D,0x00030201,24 11 | Q,0x04030201 12 | Q,0x01030201 13 | Q,0x00000000 -------------------------------------------------------------------------------- /Homework/lookup/data/lookup_output1.out: -------------------------------------------------------------------------------- 1 | 0x0109a8c0 10 2 | -------------------------------------------------------------------------------- /Homework/lookup/data/lookup_output2.out: -------------------------------------------------------------------------------- 1 | 0x0203a8c0 9 2 | 0x0203a8c0 9 3 | 0x0203a8c0 9 4 | 0x0109a8c0 10 5 | 0x0203a8c0 9 6 | -------------------------------------------------------------------------------- /Homework/lookup/data/lookup_output3.out: -------------------------------------------------------------------------------- 1 | 0x0109a8c0 10 2 | 0x0203a8c0 9 3 | Not Found 4 | -------------------------------------------------------------------------------- /Homework/lookup/data/lookup_output4.out: -------------------------------------------------------------------------------- 1 | 0x0109a8c0 10 2 | 0x0203a8c0 9 3 | Not Found 4 | 0x0203a8c0 9 5 | 0x0203a8c0 9 6 | Not Found 7 | Not Found 8 | Not Found 9 | Not Found 10 | -------------------------------------------------------------------------------- /Homework/lookup/grade.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import re 5 | import sys 6 | import os 7 | import json 8 | import subprocess 9 | import time 10 | from os.path import isfile, join 11 | import random 12 | import string 13 | import signal 14 | import glob 15 | import traceback 16 | 17 | prefix = 'lookup' 18 | exe = prefix 19 | if len(sys.argv) > 1: 20 | exe = sys.argv[1] 21 | 22 | def write_grade(grade, total): 23 | data = {} 24 | data['grade'] = grade 25 | if os.isatty(1): 26 | print('Passed: {}/{}'.format(grade, total)) 27 | else: 28 | print(json.dumps(data)) 29 | 30 | sys.exit(0) 31 | 32 | 33 | if __name__ == '__main__': 34 | 35 | if sys.version_info[0] != 3: 36 | print("Plz use python3") 37 | sys.exit() 38 | 39 | if os.isatty(1): 40 | print('Removing all output files') 41 | os.system('rm -f data/{}user*.out'.format(prefix)) 42 | 43 | total = len(glob.glob("data/{}_input*.in".format(prefix))) 44 | 45 | grade = 0 46 | 47 | for i in range(1, total+1): 48 | in_file = "data/{}_input{}.in".format(prefix, i) 49 | out_file = "data/{}_user{}.out".format(prefix, i) 50 | ans_file = "data/{}_output{}.out".format(prefix, i) 51 | 52 | if os.isatty(1): 53 | print('Running \'./{} < {} > {}\''.format(exe, in_file, out_file)) 54 | p = subprocess.Popen(['./{}'.format(exe)], stdout=open(out_file, 'w'), stdin=open(in_file, 'r')) 55 | start_time = time.time() 56 | 57 | while p.poll() is None: 58 | if time.time() - start_time > 1: 59 | p.kill() 60 | 61 | try: 62 | out = [line.strip() for line in open(out_file, 'r').readlines() if line.strip()] 63 | ans = [line.strip() for line in open(ans_file, 'r').readlines() if line.strip()] 64 | 65 | if out == ans: 66 | grade += 1 67 | elif os.isatty(1): 68 | print('Diff: ') 69 | os.system('diff -u {} {} | head -n 10'.format(out_file, ans_file)) 70 | except Exception: 71 | if os.isatty(1): 72 | print('Unexpected exception caught:') 73 | traceback.print_exc() 74 | 75 | write_grade(grade, total) 76 | 77 | -------------------------------------------------------------------------------- /Homework/lookup/lookup.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "router.h" 9 | 10 | typedef struct { 11 | uint32_t addr; 12 | uint32_t mask; 13 | uint32_t if_index; 14 | uint32_t nexthop; 15 | } Entry; 16 | 17 | std::vector table; 18 | 19 | /* 20 | RoutingTable Entry 的定义如下: 21 | typedef struct { 22 | uint32_t addr; // 大端序,IPv4 地址 23 | uint32_t len; // 小端序,前缀长度 24 | uint32_t if_index; // 小端序,出端口编号 25 | uint32_t nexthop; // 大端序,下一跳的 IPv4 地址 26 | } RoutingTableEntry; 27 | 28 | 约定 addr 和 nexthop 以 **大端序** 存储。 29 | 这意味着 1.2.3.4 对应 0x04030201 而不是 0x01020304。 30 | 保证 addr 仅最低 len 位可能出现非零。 31 | 当 nexthop 为零时这是一条直连路由。 32 | 你可以在全局变量中把路由表以一定的数据结构格式保存下来。 33 | */ 34 | 35 | /** 36 | * @brief 插入/删除一条路由表表项 37 | * @param insert 如果要插入则为 true ,要删除则为 false 38 | * @param entry 要插入/删除的表项 39 | * 40 | * 插入时如果已经存在一条 addr 和 len 都相同的表项,则替换掉原有的。 41 | */ 42 | void update(bool insert, RoutingTableEntry entry) { 43 | uint32_t addr = entry.addr, mask = (1ULL << entry.len) - 1; 44 | auto pos = std::find_if(table.begin(), table.end(), [addr, mask](const Entry &e) { return e.addr == addr && e.mask == mask; }); 45 | if (insert) { 46 | if (pos != table.end()) { 47 | pos->if_index = entry.if_index; 48 | pos->nexthop = entry.nexthop; 49 | } else { 50 | table.push_back(Entry{addr, mask, entry.if_index, entry.nexthop}); 51 | } 52 | } else if (pos != table.end()) { 53 | std::swap(*pos, table.back()); 54 | table.pop_back(); 55 | } 56 | } 57 | 58 | /** 59 | * @brief 进行一次路由表的查询,按照最长前缀匹配原则 60 | * @param addr 需要查询的目标地址,大端序 61 | * @param nexthop 如果查询到目标,把表项的 nexthop 写入 62 | * @param if_index 如果查询到目标,把表项的 if_index 写入 63 | * @return 查到则返回 true ,没查到则返回 false 64 | */ 65 | bool query(uint32_t addr, uint32_t *nexthop, uint32_t *if_index) { 66 | uint32_t max = 0; 67 | uint32_t nexthop1, if_index1; 68 | for (const auto &e : table) { 69 | if (e.mask > max && (addr & e.mask) == e.addr) { 70 | max = e.mask; 71 | nexthop1 = e.nexthop; 72 | if_index1 = e.if_index; 73 | } 74 | } 75 | if (max != 0) { 76 | *nexthop = nexthop1; 77 | *if_index = if_index1; 78 | } 79 | return max; 80 | } -------------------------------------------------------------------------------- /Homework/lookup/main.cpp: -------------------------------------------------------------------------------- 1 | #include "router_hal.h" 2 | #include "router.h" 3 | #include 4 | #include 5 | #include 6 | 7 | extern void update(bool insert, RoutingTableEntry entry); 8 | extern bool query(uint32_t addr, uint32_t *nexthop, uint32_t *if_index); 9 | char buffer[1024]; 10 | 11 | int main(int argc, char *argv[]) { 12 | uint32_t addr, len, if_index, nexthop; 13 | char tmp; 14 | while (fgets(buffer, sizeof(buffer), stdin)) { 15 | if (buffer[0] == 'I') { 16 | sscanf(buffer, "%c,%x,%d,%d,%x", &tmp, &addr, &len, &if_index, &nexthop); 17 | RoutingTableEntry entry = { 18 | .addr = addr, .len = len, .if_index = if_index, .nexthop = nexthop}; 19 | update(true, entry); 20 | } else if (buffer[0] == 'D') { 21 | sscanf(buffer, "%c,%x,%d", &tmp, &addr, &len); 22 | RoutingTableEntry entry = { 23 | .addr = addr, 24 | .len = len, 25 | .if_index = 0, 26 | .nexthop = 0 27 | }; 28 | update(false, entry); 29 | } else if (buffer[0] == 'Q') { 30 | sscanf(buffer, "%c,%x", &tmp, &addr); 31 | if (query(addr, &nexthop, &if_index)) { 32 | printf("0x%08x %d\n", nexthop, if_index); 33 | } else { 34 | printf("Not Found\n"); 35 | } 36 | } 37 | } 38 | return 0; 39 | } -------------------------------------------------------------------------------- /Homework/lookup/router.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // 路由表的一项 4 | typedef struct { 5 | uint32_t addr; // 地址 6 | uint32_t len; // 前缀长度 7 | uint32_t if_index; // 出端口编号 8 | uint32_t nexthop; // 下一条的地址,0 表示直连 9 | // 为了实现 RIP 协议,需要在这里添加额外的字段 10 | } RoutingTableEntry; 11 | -------------------------------------------------------------------------------- /Homework/protocol/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | protocol 3 | std 4 | std.cpp 5 | !*_output*.out 6 | !Makefile 7 | -------------------------------------------------------------------------------- /Homework/protocol/Makefile: -------------------------------------------------------------------------------- 1 | CXX ?= g++ 2 | LAB_ROOT ?= ../.. 3 | BACKEND ?= STDIO 4 | CXXFLAGS ?= --std=c++11 -I $(LAB_ROOT)/HAL/include -DROUTER_BACKEND_$(BACKEND) 5 | LDFLAGS ?= -lpcap 6 | 7 | .PHONY: all clean grade 8 | all: protocol 9 | 10 | clean: 11 | rm -f *.o protocol std 12 | 13 | grade: protocol 14 | python3 grade.py 15 | 16 | %.o: %.cpp 17 | $(CXX) $(CXXFLAGS) -c $^ -o $@ 18 | 19 | hal.o: $(LAB_ROOT)/HAL/src/stdio/router_hal.cpp 20 | $(CXX) $(CXXFLAGS) -c $^ -o $@ 21 | 22 | protocol: protocol.o main.o hal.o 23 | $(CXX) $^ -o $@ $(LDFLAGS) 24 | 25 | std: std.o main.o hal.o 26 | $(CXX) $^ -o $@ $(LDFLAGS) 27 | -------------------------------------------------------------------------------- /Homework/protocol/data/protocol_input1.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MashPlant/Router-Lab/d98900c038bc9b892acb430da125f460d8857760/Homework/protocol/data/protocol_input1.pcap -------------------------------------------------------------------------------- /Homework/protocol/data/protocol_input10.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MashPlant/Router-Lab/d98900c038bc9b892acb430da125f460d8857760/Homework/protocol/data/protocol_input10.pcap -------------------------------------------------------------------------------- /Homework/protocol/data/protocol_input11.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MashPlant/Router-Lab/d98900c038bc9b892acb430da125f460d8857760/Homework/protocol/data/protocol_input11.pcap -------------------------------------------------------------------------------- /Homework/protocol/data/protocol_input12.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MashPlant/Router-Lab/d98900c038bc9b892acb430da125f460d8857760/Homework/protocol/data/protocol_input12.pcap -------------------------------------------------------------------------------- /Homework/protocol/data/protocol_input2.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MashPlant/Router-Lab/d98900c038bc9b892acb430da125f460d8857760/Homework/protocol/data/protocol_input2.pcap -------------------------------------------------------------------------------- /Homework/protocol/data/protocol_input3.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MashPlant/Router-Lab/d98900c038bc9b892acb430da125f460d8857760/Homework/protocol/data/protocol_input3.pcap -------------------------------------------------------------------------------- /Homework/protocol/data/protocol_input4.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MashPlant/Router-Lab/d98900c038bc9b892acb430da125f460d8857760/Homework/protocol/data/protocol_input4.pcap -------------------------------------------------------------------------------- /Homework/protocol/data/protocol_input5.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MashPlant/Router-Lab/d98900c038bc9b892acb430da125f460d8857760/Homework/protocol/data/protocol_input5.pcap -------------------------------------------------------------------------------- /Homework/protocol/data/protocol_input6.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MashPlant/Router-Lab/d98900c038bc9b892acb430da125f460d8857760/Homework/protocol/data/protocol_input6.pcap -------------------------------------------------------------------------------- /Homework/protocol/data/protocol_input7.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MashPlant/Router-Lab/d98900c038bc9b892acb430da125f460d8857760/Homework/protocol/data/protocol_input7.pcap -------------------------------------------------------------------------------- /Homework/protocol/data/protocol_input8.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MashPlant/Router-Lab/d98900c038bc9b892acb430da125f460d8857760/Homework/protocol/data/protocol_input8.pcap -------------------------------------------------------------------------------- /Homework/protocol/data/protocol_input9.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MashPlant/Router-Lab/d98900c038bc9b892acb430da125f460d8857760/Homework/protocol/data/protocol_input9.pcap -------------------------------------------------------------------------------- /Homework/protocol/data/protocol_output1.out: -------------------------------------------------------------------------------- 1 | Valid 1 2 2 | 0005a8c0 00ffffff 00000000 01000000 3 | 02 02 00 00 00 02 00 00 c0 a8 05 00 ff ff ff 00 00 00 00 00 00 00 00 01 4 | Valid 1 2 5 | 0005a8c0 00ffffff 00000000 01000000 6 | 02 02 00 00 00 02 00 00 c0 a8 05 00 ff ff ff 00 00 00 00 00 00 00 00 01 7 | -------------------------------------------------------------------------------- /Homework/protocol/data/protocol_output10.out: -------------------------------------------------------------------------------- 1 | Valid 1 2 2 | 0005a8c0 00ffffff 00000000 01000000 3 | 02 02 00 00 00 02 00 00 c0 a8 05 00 ff ff ff 00 00 00 00 00 00 00 00 01 4 | Invalid 5 | -------------------------------------------------------------------------------- /Homework/protocol/data/protocol_output11.out: -------------------------------------------------------------------------------- 1 | Valid 1 2 2 | 0005a8c0 00ffffff 00000000 01000000 3 | 02 02 00 00 00 02 00 00 c0 a8 05 00 ff ff ff 00 00 00 00 00 00 00 00 01 4 | Invalid 5 | -------------------------------------------------------------------------------- /Homework/protocol/data/protocol_output12.out: -------------------------------------------------------------------------------- 1 | Valid 1 2 2 | 0005a8c0 00ffffff 00000000 01000000 3 | 02 02 00 00 00 02 00 00 c0 a8 05 00 ff ff ff 00 00 00 00 00 00 00 00 01 4 | Invalid 5 | -------------------------------------------------------------------------------- /Homework/protocol/data/protocol_output2.out: -------------------------------------------------------------------------------- 1 | Valid 1 2 2 | 0005a8c0 00ffffff 00000000 01000000 3 | 02 02 00 00 00 02 00 00 c0 a8 05 00 ff ff ff 00 00 00 00 00 00 00 00 01 4 | Valid 1 2 5 | 0005a8c0 00ffffff 00000000 10000000 6 | 02 02 00 00 00 02 00 00 c0 a8 05 00 ff ff ff 00 00 00 00 00 00 00 00 10 7 | -------------------------------------------------------------------------------- /Homework/protocol/data/protocol_output3.out: -------------------------------------------------------------------------------- 1 | Valid 3 2 2 | 0005a8c0 00ffffff 00000000 01000000 3 | 0006a8c0 00ffffff 00000000 01000000 4 | 0007a8c0 00ffffff 00000000 01000000 5 | 02 02 00 00 00 02 00 00 c0 a8 05 00 ff ff ff 00 00 00 00 00 00 00 00 01 00 02 00 00 c0 a8 06 00 ff ff ff 00 00 00 00 00 00 00 00 01 00 02 00 00 c0 a8 07 00 ff ff ff 00 00 00 00 00 00 00 00 01 6 | -------------------------------------------------------------------------------- /Homework/protocol/data/protocol_output4.out: -------------------------------------------------------------------------------- 1 | Valid 1 1 2 | 00000000 00000000 00000000 10000000 3 | 01 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 4 | -------------------------------------------------------------------------------- /Homework/protocol/data/protocol_output5.out: -------------------------------------------------------------------------------- 1 | Valid 3 2 2 | 0005a8c0 00ffffff 00000000 01000000 3 | 0006a8c0 00ffffff 00000000 01000000 4 | 0007a8c0 00ffffff 00000000 01000000 5 | 02 02 00 00 00 02 00 00 c0 a8 05 00 ff ff ff 00 00 00 00 00 00 00 00 01 00 02 00 00 c0 a8 06 00 ff ff ff 00 00 00 00 00 00 00 00 01 00 02 00 00 c0 a8 07 00 ff ff ff 00 00 00 00 00 00 00 00 01 6 | Invalid 7 | -------------------------------------------------------------------------------- /Homework/protocol/data/protocol_output6.out: -------------------------------------------------------------------------------- 1 | Valid 1 2 2 | 0005a8c0 00ffffff 00000000 01000000 3 | 02 02 00 00 00 02 00 00 c0 a8 05 00 ff ff ff 00 00 00 00 00 00 00 00 01 4 | Invalid 5 | Valid 1 2 6 | 0005a8c0 00ffffff 00000000 10000000 7 | 02 02 00 00 00 02 00 00 c0 a8 05 00 ff ff ff 00 00 00 00 00 00 00 00 10 8 | Invalid 9 | -------------------------------------------------------------------------------- /Homework/protocol/data/protocol_output7.out: -------------------------------------------------------------------------------- 1 | Invalid 2 | -------------------------------------------------------------------------------- /Homework/protocol/data/protocol_output8.out: -------------------------------------------------------------------------------- 1 | Valid 1 2 2 | 0005a8c0 00ffffff 00000000 01000000 3 | 02 02 00 00 00 02 00 00 c0 a8 05 00 ff ff ff 00 00 00 00 00 00 00 00 01 4 | Invalid 5 | -------------------------------------------------------------------------------- /Homework/protocol/data/protocol_output9.out: -------------------------------------------------------------------------------- 1 | Valid 1 2 2 | 0005a8c0 00ffffff 00000000 01000000 3 | 02 02 00 00 00 02 00 00 c0 a8 05 00 ff ff ff 00 00 00 00 00 00 00 00 01 4 | Invalid 5 | -------------------------------------------------------------------------------- /Homework/protocol/grade.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import re 5 | import sys 6 | import os 7 | import json 8 | import subprocess 9 | import time 10 | from os.path import isfile, join 11 | import random 12 | import string 13 | import signal 14 | import glob 15 | import traceback 16 | 17 | prefix = 'protocol' 18 | exe = prefix 19 | if len(sys.argv) > 1: 20 | exe = sys.argv[1] 21 | 22 | def write_grade(grade, total): 23 | data = {} 24 | data['grade'] = grade 25 | if os.isatty(1): 26 | print('Passed: {}/{}'.format(grade, total)) 27 | else: 28 | print(json.dumps(data)) 29 | 30 | sys.exit(0) 31 | 32 | 33 | if __name__ == '__main__': 34 | 35 | if sys.version_info[0] != 3: 36 | print("Plz use python3") 37 | sys.exit() 38 | 39 | if os.isatty(1): 40 | print('Removing all output files') 41 | os.system('rm -f data/{}user*.out'.format(prefix)) 42 | 43 | total = len(glob.glob("data/{}_input*.pcap".format(prefix))) 44 | 45 | grade = 0 46 | 47 | for i in range(1, total+1): 48 | in_file = "data/{}_input{}.pcap".format(prefix, i) 49 | out_file = "data/{}_user{}.out".format(prefix, i) 50 | ans_file = "data/{}_output{}.out".format(prefix, i) 51 | 52 | if os.isatty(1): 53 | print('Running \'./{} < {} > {}\''.format(exe, in_file, out_file)) 54 | p = subprocess.Popen(['./{}'.format(exe)], stdout=open(out_file, 'w'), stdin=open(in_file, 'r')) 55 | start_time = time.time() 56 | 57 | while p.poll() is None: 58 | if time.time() - start_time > 1: 59 | p.kill() 60 | 61 | try: 62 | out = [line.strip() for line in open(out_file, 'r').readlines() if line.strip()] 63 | ans = [line.strip() for line in open(ans_file, 'r').readlines() if line.strip()] 64 | 65 | if out == ans: 66 | grade += 1 67 | elif os.isatty(1): 68 | print('Diff: ') 69 | os.system('diff -u {} {} | head -n 10'.format(out_file, ans_file)) 70 | except Exception: 71 | if os.isatty(1): 72 | print('Unexpected exception caught:') 73 | traceback.print_exc() 74 | 75 | write_grade(grade, total) 76 | 77 | -------------------------------------------------------------------------------- /Homework/protocol/main.cpp: -------------------------------------------------------------------------------- 1 | #include "router_hal.h" 2 | #include "rip.h" 3 | #include 4 | #include 5 | #include 6 | 7 | extern bool disassemble(const uint8_t *packet, uint32_t len, RipPacket *output); 8 | extern uint32_t assemble(const RipPacket *rip, uint8_t *buffer); 9 | uint8_t buffer[1024]; 10 | uint8_t packet[2048]; 11 | RipPacket rip; 12 | in_addr_t addrs[N_IFACE_ON_BOARD] = {0}; 13 | 14 | int main(int argc, char *argv[]) { 15 | int res = HAL_Init(0, addrs); 16 | if (res < 0) { 17 | return res; 18 | } 19 | while (1) { 20 | int mask = (1 << N_IFACE_ON_BOARD) - 1; 21 | macaddr_t src_mac; 22 | macaddr_t dst_mac; 23 | int if_index; 24 | res = HAL_ReceiveIPPacket(mask, packet, sizeof(packet), src_mac, 25 | dst_mac, -1, &if_index); 26 | if (res == HAL_ERR_EOF) { 27 | break; 28 | } else if (res < 0) { 29 | return res; 30 | } 31 | if (disassemble(packet, res, &rip)) { 32 | printf("Valid %d %d\n", rip.numEntries, rip.command); 33 | for (int i = 0;i < rip.numEntries;i++) { 34 | printf("%08x %08x %08x %08x\n", rip.entries[i].addr, rip.entries[i].mask, rip.entries[i].nexthop, rip.entries[i].metric); 35 | } 36 | uint32_t len = assemble(&rip, buffer); 37 | for (uint32_t i = 0;i < len;i++) { 38 | printf("%02x ", buffer[i]); 39 | } 40 | printf("\n"); 41 | } else { 42 | printf("Invalid\n"); 43 | } 44 | } 45 | return 0; 46 | } -------------------------------------------------------------------------------- /Homework/protocol/protocol.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "rip.h" 7 | 8 | using u8 = uint8_t; 9 | using u16 = uint16_t; 10 | using u32 = uint32_t; 11 | 12 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 13 | #define BE16(x) __builtin_bswap16(x) 14 | #define BE32(x) __builtin_bswap32(x) 15 | #else 16 | #define BE16(x) x 17 | #define BE32(x) x 18 | #endif 19 | 20 | struct iphdr { 21 | u8 ihl : 4, version : 4; 22 | u8 tos; 23 | u16 tot_len; 24 | u16 id; 25 | u16 frag_off; 26 | u8 ttl; 27 | u8 protocol; 28 | u16 check; 29 | u32 saddr; 30 | u32 daddr; 31 | }; 32 | 33 | struct RawRip { 34 | u8 command; // 1(request) or 2(reponse) 35 | u8 version; // 2 36 | u16 zero; 37 | struct Entry { 38 | u16 family; // 0(request) or 2(response) 39 | u16 tag; // 0 40 | u32 addr; 41 | u32 mask; // todo 42 | u32 nexthop; 43 | u32 metric; // [1, 16] 44 | } entries[0]; 45 | }; 46 | 47 | /* 48 | 在头文件 rip.h 中定义了如下的结构体: 49 | #define RIP_MAX_ENTRY 25 50 | typedef struct { 51 | // all fields are big endian 52 | // we don't store 'family', as it is always 2(response) and 0(request) 53 | // we don't store 'tag', as it is always 0 54 | uint32_t addr; 55 | uint32_t mask; 56 | uint32_t nexthop; 57 | uint32_t metric; 58 | } RipEntry; 59 | 60 | typedef struct { 61 | uint32_t numEntries; 62 | // all fields below are big endian 63 | uint8_t command; // 1 for request, 2 for response, otherwsie invalid 64 | // we don't store 'version', as it is always 2 65 | // we don't store 'zero', as it is always 0 66 | RipEntry entries[RIP_MAX_ENTRY]; 67 | } RipPacket; 68 | 69 | 你需要从 IPv4 包中解析出 RipPacket 结构体,也要从 RipPacket 结构体构造出对应的 IP 包 70 | 由于 Rip 包结构本身不记录表项的个数,需要从 IP 头的长度中推断,所以在 RipPacket 中额外记录了个数。 71 | 需要注意这里的地址都是用 **大端序** 存储的,1.2.3.4 对应 0x04030201 。 72 | */ 73 | 74 | /** 75 | * @brief 从接受到的 IP 包解析出 Rip 协议的数据 76 | * @param packet 接受到的 IP 包 77 | * @param len 即 packet 的长度 78 | * @param output 把解析结果写入 *output 79 | * @return 如果输入是一个合法的 RIP 包,把它的内容写入 RipPacket 并且返回 true;否则返回 false 80 | * 81 | * IP 包的 Total Length 长度可能和 len 不同,当 Total Length 大于 len 时,把传入的 IP 包视为不合法。 82 | * 你不需要校验 IP 头和 UDP 的校验和是否合法。 83 | * 你需要检查 Command 是否为 1 或 2,Version 是否为 2, Zero 是否为 0, 84 | * Family 和 Command 是否有正确的对应关系,Tag 是否为 0, 85 | * Metric 转换成小端序后是否在 [1,16] 的区间内, 86 | * Mask 的二进制是不是连续的 1 与连续的 0 组成等等。 87 | */ 88 | bool disassemble(const uint8_t *packet, uint32_t len, RipPacket *output) { 89 | #define REQUIRE(x) \ 90 | if (!(x)) return false; 91 | 92 | iphdr *hdr = (iphdr *)packet; 93 | if (BE16(hdr->tot_len) > len) return false; 94 | u32 off = hdr->ihl * 4 + 8; // 8 is udp header size 95 | u32 count = (len - off - 4) / 20; // 4 is rip header size, 20 is entry size 96 | const RawRip *raw = (const RawRip *)(packet + off); 97 | bool request; 98 | if (raw->command == 1) { 99 | request = true; 100 | } else if (raw->command == 2) { 101 | request = false; 102 | } else { 103 | return false; 104 | } 105 | REQUIRE(raw->version == 2); 106 | REQUIRE(raw->zero == 0); 107 | output->numEntries = count; 108 | output->command = raw->command; 109 | for (u32 i = 0; i < count; ++i) { 110 | const RawRip::Entry *src = &raw->entries[i]; 111 | u16 family = BE16(src->family); 112 | REQUIRE((request && family == 0) || (!request && family == 2)); 113 | REQUIRE(src->tag == 0); 114 | u32 metric = BE32(src->metric); 115 | REQUIRE(1 <= metric && metric <= 16); 116 | u32 mask = BE32(src->mask); 117 | REQUIRE(mask == 0 || (mask | ((1 << __builtin_ctz(mask)) - 1)) == ~0); 118 | memcpy(&output->entries[i].addr, &src->addr, 4 * sizeof(u32)); 119 | } 120 | return true; 121 | } 122 | 123 | /** 124 | * @brief 从 RipPacket 的数据结构构造出 RIP 协议的二进制格式 125 | * @param rip 一个 RipPacket 结构体 126 | * @param buffer 一个足够大的缓冲区,你要把 RIP 协议的数据写进去 127 | * @return 写入 buffer 的数据长度 128 | * 129 | * 在构造二进制格式的时候,你需要把 RipPacket 中没有保存的一些固定值补充上,包括 Version、Zero、Address Family 和 Route Tag 这四个字段 130 | * 你写入 buffer 的数据长度和返回值都应该是四个字节的 RIP 头,加上每项 20 字节。 131 | * 需要注意一些没有保存在 RipPacket 结构体内的数据的填写。 132 | */ 133 | uint32_t assemble(const RipPacket *rip, uint8_t *buffer) { 134 | RawRip *raw = (RawRip *)buffer; 135 | u32 count = rip->numEntries; 136 | raw->command = rip->command; 137 | raw->version = 2; 138 | raw->zero = 0; 139 | u16 family = rip->command == 1 ? 0 : BE16(2); 140 | for (u32 i = 0; i < count; ++i) { 141 | RawRip::Entry *dst = &raw->entries[i]; 142 | dst->family = family; 143 | dst->tag = 0; 144 | memcpy(&dst->addr, &rip->entries[i], 4 * sizeof(u32)); 145 | } 146 | return 4 + 20 * count; 147 | } 148 | -------------------------------------------------------------------------------- /Homework/protocol/rip.h: -------------------------------------------------------------------------------- 1 | #include 2 | #define RIP_MAX_ENTRY 25 3 | typedef struct { 4 | // all fields are big endian 5 | // we don't store 'family', as it is always 2(response) and 0(request) 6 | // we don't store 'tag', as it is always 0 7 | uint32_t addr; 8 | uint32_t mask; 9 | uint32_t nexthop; 10 | uint32_t metric; 11 | } RipEntry; 12 | 13 | typedef struct { 14 | uint32_t numEntries; 15 | // all fields below are big endian 16 | uint8_t command; 17 | // we don't store 'version', as it is always 2 18 | // we don't store 'zero', as it is always 0 19 | RipEntry entries[RIP_MAX_ENTRY]; 20 | } RipPacket; -------------------------------------------------------------------------------- /Homework/router/Makefile: -------------------------------------------------------------------------------- 1 | CXX ?= g++ 2 | LAB_ROOT ?= ../.. 3 | BACKEND ?= LINUX 4 | CXXFLAGS ?= -Ofast --std=c++11 -I $(LAB_ROOT)/HAL/include -DROUTER_BACKEND_$(BACKEND) 5 | LDFLAGS ?= -lpcap 6 | 7 | .PHONY: all clean 8 | all: router.out 9 | 10 | clean: 11 | rm -f *.o *.out 12 | 13 | hal.o: $(LAB_ROOT)/HAL/src/linux/router_hal.cpp 14 | $(CXX) $(CXXFLAGS) -c $^ -o $@ 15 | 16 | router.out: main.cpp hal.o 17 | $(CXX) -Wconversion -Wall -Wextra $(CXXFLAGS) $^ -o $@ $(LDFLAGS) 18 | -------------------------------------------------------------------------------- /Homework/router/addr2u32.py: -------------------------------------------------------------------------------- 1 | s = input() 2 | s = list(map(lambda x: hex(int(x))[2:].zfill(2), s.split('.'))) 3 | print(f'0x{s[3]}{s[2]}{s[1]}{s[0]}') 4 | -------------------------------------------------------------------------------- /Homework/router/main.cpp: -------------------------------------------------------------------------------- 1 | #include "router_hal.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using u8 = uint8_t; 9 | using u16 = uint16_t; 10 | using u32 = uint32_t; 11 | using u64 = uint64_t; 12 | using i32 = int32_t; 13 | 14 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 15 | #define BE16(x) __builtin_bswap16(x) 16 | #define BE32(x) __builtin_bswap32(x) 17 | #else 18 | #define BE16(x) x 19 | #define BE32(x) x 20 | #endif 21 | 22 | const u32 RIP_MULITCAST_ADDR = 0x090000e0; 23 | 24 | struct IpHdr { 25 | u8 ihl : 4, version : 4; 26 | u8 tos; 27 | u16 tot_len; 28 | u16 id; 29 | u16 frag_off; 30 | u8 ttl; 31 | u8 protocol; 32 | u16 check; 33 | u32 saddr; 34 | u32 daddr; 35 | } __attribute__((aligned(4))); 36 | 37 | struct UdpHdr { 38 | u16 src; 39 | u16 dst; 40 | u16 len; 41 | u16 chksum; 42 | } __attribute__((aligned(4))); 43 | 44 | u16 calc_check_sum(IpHdr *ip) { 45 | u16 old = ip->check; 46 | ip->check = 0; 47 | u32 sum = 0; 48 | for (u16 *p = (u16 *)ip, *end = p + ip->ihl * 2; p < end; ++p) { 49 | sum += BE16(*p); 50 | } 51 | ip->check = old; 52 | sum = (sum & 0xFFFF) + (sum >> 16); 53 | sum = (sum & 0xFFFF) + (sum >> 16); 54 | return (u16)~sum; 55 | } 56 | 57 | struct RouteEntry { 58 | u32 addr; // big endian, e.g., 1.2.3.4 is 0x04030201 rather than 0x01020304 59 | u32 mask; // big endian 60 | u32 nexthop; // big endian, nexthop == 0 means direct routing 61 | u32 metric; // big endian, two big endian metrics can be compared directly 62 | u32 if_index; // machine endian 63 | }; 64 | 65 | std::vector table; 66 | 67 | bool query(u32 addr, u32 *nexthop, u32 *if_index) { 68 | u32 max = 0; 69 | u32 nexthop1, if_index1; 70 | for (auto &e : table) { 71 | if (e.mask > max && (addr & e.mask) == e.addr) { 72 | max = e.mask; 73 | nexthop1 = e.nexthop; 74 | if_index1 = e.if_index; 75 | } 76 | } 77 | if (max != 0) { 78 | *nexthop = nexthop1; 79 | *if_index = if_index1; 80 | } 81 | return max; 82 | } 83 | 84 | struct RawRip { 85 | u8 command; // 1(request) or 2(reponse) 86 | u8 version; // 2 87 | u16 zero; 88 | struct Entry { 89 | u16 family; // 0(request) or 2(response) 90 | u16 tag; // 0 91 | u32 addr; 92 | u32 mask; 93 | u32 nexthop; 94 | u32 metric; // [1, 16] 95 | } entries[]; 96 | } __attribute__((aligned(4))); 97 | 98 | bool check_rip(IpHdr *ip, u32 len) { 99 | #define REQUIRE(x) \ 100 | if (!(x)) \ 101 | return false; 102 | 103 | if (BE16(ip->tot_len) > len) 104 | return false; 105 | u32 off = ip->ihl * 4 + 8; // 8 is udp header size 106 | u32 count = (len - off - 4) / 20; // 4 is rip header size, 20 is entry size 107 | RawRip *raw = (RawRip *)((u8 *)ip + off); 108 | bool request; 109 | if (raw->command == 1) { 110 | request = true; 111 | } else if (raw->command == 2) { 112 | request = false; 113 | } else { 114 | return false; 115 | } 116 | REQUIRE(raw->version == 2); 117 | REQUIRE(raw->zero == 0); 118 | for (u32 i = 0; i < count; ++i) { 119 | RawRip::Entry &e = raw->entries[i]; 120 | u16 family = BE16(e.family); 121 | REQUIRE((request && family == 0) || (!request && family == 2)); 122 | REQUIRE(e.tag == 0); 123 | u32 metric = BE32(e.metric); 124 | REQUIRE(1 <= metric && metric <= 16); 125 | u32 mask = BE32(e.mask); 126 | REQUIRE(mask == 0 || (mask | ((1 << __builtin_ctz(mask)) - 1)) == ~0u); 127 | } 128 | return true; 129 | } 130 | 131 | __attribute__((aligned(4))) u8 packet[2048]; 132 | 133 | // 0: 192.168.3.2 134 | // 1: 192.168.4.1 135 | // 2: 10.0.2.1 136 | // 3: 10.0.3.1 137 | u32 addrs[N_IFACE_ON_BOARD] = {0x0203a8c0, 0x0104a8c0, 0x0102000a, 0x0103000a}; 138 | macaddr_t multicast_mac = {0x01, 0x00, 0x5e, 0x00, 0x00, 0x09}; 139 | 140 | // `iface` == -1u means send to all interfaces 141 | void send_response(u32 iface, u32 dst_addr) { 142 | #define SEND_ALL() \ 143 | do { \ 144 | u32 tot_len = 20 + 8 + 4 + cnt * 20; \ 145 | ip->tot_len = BE16((u16)tot_len); \ 146 | ip->check = BE16(calc_check_sum(ip)); \ 147 | udp->len = BE16((u16)(tot_len - 20)); \ 148 | if (HAL_ArpGetMacAddress(i, dst_addr, dst_mac) == 0) { \ 149 | HAL_SendIPPacket(i, packet, tot_len, dst_mac); \ 150 | } \ 151 | } while (false) 152 | IpHdr *ip = (IpHdr *)packet; 153 | UdpHdr *udp = (UdpHdr *)(packet + 20); 154 | RawRip *rip = (RawRip *)(packet + 28); 155 | macaddr_t dst_mac; 156 | *ip = IpHdr{ 157 | .ihl = 5, 158 | .version = 4, 159 | .tos = 0, 160 | .tot_len = 0, // set later 161 | .id = 0, 162 | .frag_off = 0, 163 | .ttl = 1, 164 | .protocol = 17, // udp 165 | .check = 0, // set later 166 | .saddr = 0, // set later 167 | .daddr = dst_addr, 168 | }; 169 | *udp = UdpHdr{.src = BE16(520), .dst = BE16(520), .len = 0 /* set later */, .chksum = 0}; 170 | rip->command = 2; // response 171 | rip->version = 2; 172 | rip->zero = 0; 173 | for (u32 i = 0; i < N_IFACE_ON_BOARD; ++i) { 174 | if (iface == -1u || iface == i) { 175 | ip->saddr = addrs[i]; 176 | u32 cnt = 0; 177 | for (auto &e1 : table) { 178 | if (e1.nexthop == 0 || e1.if_index != i) { // split horizon 179 | RawRip::Entry &e2 = rip->entries[cnt]; 180 | e2.family = BE16(2); 181 | e2.tag = 0; 182 | e2.addr = e1.addr; 183 | e2.mask = e1.mask; 184 | e2.nexthop = 0; 185 | e2.metric = e1.metric; 186 | if (++cnt == 25) { 187 | SEND_ALL(); 188 | cnt = 0; 189 | } 190 | } 191 | } 192 | if (cnt != 0) { 193 | SEND_ALL(); 194 | } 195 | } 196 | } 197 | } 198 | 199 | #define IP_FMT(x) x >> 24, x >> 16 & 0xFF, x >> 8 & 0xFF, x & 0xFF 200 | 201 | void print_table() { 202 | u32 size = (u32)table.size(); 203 | printf("table: count = %d, last 25 elements = [\n", size); 204 | for (u32 i = size > 25 ? size - 25 : 0; i < size; ++i) { 205 | RouteEntry &e = table[i]; 206 | u32 addr = BE32(e.addr), nexthop = BE32(e.nexthop); 207 | printf(" { addr: %d.%d.%d.%d, mask: %x, nexthop: %d.%d.%d.%d, metric: %d, if_index: %d},\n", 208 | IP_FMT(addr), BE32(e.mask), IP_FMT(nexthop), BE32(e.metric), e.if_index); 209 | } 210 | printf("]\n"); 211 | } 212 | 213 | i32 main() { 214 | i32 res = HAL_Init(1, addrs); 215 | if (res < 0) { 216 | return res; 217 | } 218 | 219 | // Add direct routes 220 | for (u32 i = 0; i < N_IFACE_ON_BOARD; i++) { 221 | table.push_back(RouteEntry{ 222 | .addr = addrs[i] & ((1 << 24) - 1), 223 | .mask = (1 << 24) - 1, 224 | .nexthop = 0, 225 | .metric = BE32(1), 226 | .if_index = i, 227 | }); 228 | } 229 | { // initially send RIP Request to all interfaces 230 | IpHdr *ip = (IpHdr *)packet; 231 | UdpHdr *udp = (UdpHdr *)(packet + 20); 232 | RawRip *rip = (RawRip *)(packet + 28); 233 | u32 tot_len = 20 + 8 + 4 + 20; // 1 entry 234 | *ip = IpHdr{ 235 | .ihl = 5, 236 | .version = 4, 237 | .tos = 0, 238 | .tot_len = BE16((u16)tot_len), 239 | .id = 0, 240 | .frag_off = 0, 241 | .ttl = 1, 242 | .protocol = 17, // udp 243 | .check = 0, // set later 244 | .saddr = 0, // set later 245 | .daddr = RIP_MULITCAST_ADDR, 246 | }; 247 | *udp = UdpHdr{.src = BE16(520), .dst = BE16(520), .len = BE16((u16)(tot_len - 20)), .chksum = 0}; 248 | rip->command = 1; // request 249 | rip->version = 2; 250 | rip->zero = 0; 251 | rip->entries[0] = RawRip::Entry{ 252 | .family = 0, 253 | .tag = 0, 254 | .addr = 0, // addr, mask nexthtop not used in a request 255 | .mask = 0, 256 | .nexthop = 0, 257 | .metric = BE32(16), // infinity 258 | }; 259 | for (u32 i = 0; i < N_IFACE_ON_BOARD; ++i) { 260 | ip->saddr = addrs[i]; 261 | ip->check = BE16(calc_check_sum(ip)); 262 | HAL_SendIPPacket(i, packet, tot_len, multicast_mac); 263 | } 264 | } 265 | 266 | u64 last_time = 0; 267 | while (1) { 268 | u64 time = HAL_GetTicks(); 269 | if (time > last_time + 5 * 1000) { 270 | printf("5s Timer\n"); 271 | print_table(); 272 | last_time = time; 273 | send_response(-1u, RIP_MULITCAST_ADDR); 274 | } 275 | macaddr_t src_mac; 276 | macaddr_t dst_mac; 277 | u32 if_index; 278 | res = HAL_ReceiveIPPacket((1 << N_IFACE_ON_BOARD) - 1, packet, sizeof(packet), src_mac, dst_mac, 1000, (i32 *)&if_index); 279 | if (res == HAL_ERR_EOF) { 280 | break; 281 | } else if (res < 0) { 282 | return res; 283 | } else if (res == 0) { 284 | // Timeout 285 | continue; 286 | } else if (res > (i32)sizeof(packet)) { 287 | // packet is truncated, ignore it 288 | continue; 289 | } 290 | IpHdr *ip = (IpHdr *)packet; 291 | 292 | if (calc_check_sum(ip) != BE16(ip->check)) { 293 | printf("Invalid IP Checksum\n"); 294 | continue; 295 | } 296 | u32 src_addr = ip->saddr, dst_addr = ip->daddr; 297 | 298 | // assume N_IFACE_ON_BOARD == 4 299 | bool dst_is_me = dst_addr == RIP_MULITCAST_ADDR || dst_addr == addrs[0] || dst_addr == addrs[1] || dst_addr == addrs[2] || dst_addr == addrs[3]; 300 | 301 | if (dst_is_me) { 302 | if (check_rip(ip, res)) { 303 | u32 off = ip->ihl * 4 + 8; // 8 is udp header size 304 | u32 rip_count = (res - off - 4) / 20; // 4 is rip header size, 20 is entry size 305 | RawRip *rip = (RawRip *)(packet + off); 306 | if (rip->command == 1) { // request 307 | send_response(if_index, src_addr); 308 | } else { // response 309 | for (u32 i = 0; i < rip_count; ++i) { 310 | u32 mask = rip->entries[i].mask; 311 | u32 addr = rip->entries[i].addr & mask; 312 | u32 metric = std::min(BE32(16), rip->entries[i].metric + BE32(1)); 313 | auto it = std::find_if(table.begin(), table.end(), 314 | [addr, mask](RouteEntry &e) { return e.addr == addr && e.mask == mask; }); 315 | if (it != table.end()) { 316 | if (it->nexthop == src_addr) { 317 | if ((it->metric = metric) == BE32(16)) { 318 | std::swap(*it, table.back()); 319 | table.pop_back(); 320 | } 321 | } else if (it->metric > metric) { 322 | it->nexthop = src_addr; 323 | it->metric = metric; 324 | it->if_index = if_index; 325 | } 326 | } else { 327 | table.push_back(RouteEntry{addr, mask, src_addr, metric, if_index}); 328 | } 329 | } 330 | } 331 | } 332 | } else { // forward 333 | u32 nexthop, dest_if; 334 | if (query(dst_addr, &nexthop, &dest_if)) { 335 | macaddr_t dest_mac; 336 | // direct routing 337 | if (nexthop == 0) { 338 | nexthop = dst_addr; 339 | } 340 | if (HAL_ArpGetMacAddress(dest_if, nexthop, dest_mac) == 0) { 341 | if (ip->ttl == 0) { 342 | // todo: send icmp tle 343 | } else { 344 | // naive checksum 345 | // --ip->ttl; 346 | // ip->check = BE16(calc_check_sum(ip)); 347 | // incremental checksum 348 | u16 old = BE16(ip->check); 349 | --ip->ttl; 350 | u32 sum = old + 0x100; 351 | sum = (sum & 0xFFFF) + (sum >> 16); 352 | ip->check = BE16((u16)(sum == 0xFFFF ? 0 : sum)); 353 | HAL_SendIPPacket(dest_if, packet, res, dest_mac); 354 | } 355 | } else { 356 | // not found, you can drop it 357 | printf("ARP not found for %x\n", nexthop); 358 | } 359 | } else { 360 | // not found, optionally you can send ICMP Host Unreachable 361 | printf("IP not found for %x\n", dst_addr); 362 | } 363 | } 364 | } 365 | return 0; 366 | } 367 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 我删掉了框架中一些介绍性的内容,想了解框架的具体信息可以直接参考[框架的仓库](https://github.com/z4yx/Router-Lab)。我这个仓库中的框架部分的代码不一定是最新的。 2 | 3 | 最终路由器的实现在[Homework/router](Homework/router),全部写在一个文件里了,直接make即可。 4 | 5 | 报告见[report.pdf](report.pdf)。 -------------------------------------------------------------------------------- /report.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MashPlant/Router-Lab/d98900c038bc9b892acb430da125f460d8857760/report.pdf --------------------------------------------------------------------------------