├── IMap-workflow.png ├── src ├── server │ ├── run.sh │ ├── meson.build │ ├── common.h │ ├── Makefile │ ├── main.c │ └── parser.c ├── switch │ ├── imap.h │ ├── iparser.h │ ├── ichannel.h │ ├── iparser.c │ ├── p4src │ │ ├── parser.p4 │ │ └── header.p4 │ ├── iswitch.h │ ├── imap.c │ ├── ichannel.c │ └── iswitch.c └── iconfig.h ├── .editorconfig ├── .gitignore ├── Makefile └── README.md /IMap-workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IMapScanner/IMap/HEAD/IMap-workflow.png -------------------------------------------------------------------------------- /src/server/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sudo build/imap-result-server -l 0-3 -n 2 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | # all files 5 | [*] 6 | indent_style = tab 7 | indent_size = 4 8 | -------------------------------------------------------------------------------- /src/server/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright(c) 2017 Intel Corporation 3 | 4 | # meson file, for building this example as part of a main DPDK build. 5 | # 6 | # To build this example as a standalone application with an already-installed 7 | # DPDK instance, use 'make' 8 | 9 | # Enable experimental API flag as l2fwd uses rte_ethdev_set_ptype API 10 | allow_experimental_apis = true 11 | sources = files( 12 | 'main.c' 13 | ) 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | *.pyc 10 | 11 | # Precompiled Headers 12 | *.gch 13 | *.pch 14 | 15 | # Compiled Dynamic libraries 16 | *.so 17 | *.dylib 18 | *.dll 19 | 20 | # Fortran module files 21 | *.mod 22 | *.smod 23 | 24 | # Compiled Static libraries 25 | *.lai 26 | *.la 27 | *.a 28 | *.lib 29 | 30 | # Executables 31 | *.exe 32 | *.out 33 | *.app 34 | 35 | # Log file 36 | *.log* 37 | zlog* 38 | 39 | # IDE 40 | .vscode 41 | 42 | # IMap Target 43 | imap 44 | imap-result-server 45 | src/server/build 46 | -------------------------------------------------------------------------------- /src/switch/imap.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: imap.h 3 | > Author: Guanyu Li 4 | > Mail: dracula.guanyu.li@gmail.com 5 | > Created Time: Mon 14 Dec 2020 10:23:02 AM CST 6 | > Description: Header file for main program of IMap 7 | ************************************************************************/ 8 | 9 | #ifndef _IMAP_H 10 | #define _IMAP_H 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #define ARRLEN(arr) sizeof(arr)/sizeof(arr[0]) 22 | 23 | #endif -------------------------------------------------------------------------------- /src/switch/iparser.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: iparser.h 3 | > Author: Cheng Guo 4 | > Mail: aeromarisa@gmail.com 5 | > Created Time: Tue 29 Jun 2021 13:47:02 PM CST 6 | > Description: Config file parser for IMap 7 | ************************************************************************/ 8 | 9 | #ifndef _IPARSER_H 10 | #define _IPARSER_H 11 | 12 | static void ip_space_list_parse(FILE *fd, long start_fptr, 13 | probe_entry_t **probe_ip_space, 14 | uint32_t *probe_ip_space_count); 15 | 16 | void config_file_parse(const char *config_filename, 17 | probe_entry_t **probe_ip_space, 18 | uint32_t *probe_ip_space_count); 19 | 20 | #endif -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: switch imap-p4 imap server clean 2 | 3 | switch: imap-p4 imap 4 | 5 | imap-p4: src/switch/p4src/imap.p4 \ 6 | src/switch/p4src/header.p4 src/switch/p4src/parser.p4 7 | $$SDE/p4_build.sh src/switch/p4src/imap.p4 8 | 9 | imap: src/iconfig.h src/switch/iswitch.h src/switch/iswitch.c \ 10 | src/switch/ichannel.h src/switch/ichannel.c \ 11 | src/switch/iparser.h src/switch/iparser.c \ 12 | src/switch/imap.h src/switch/imap.c 13 | gcc -I$$SDE_INSTALL/include -g -O2 -std=gnu11 \ 14 | -L/usr/local/lib -L$$SDE_INSTALL/lib \ 15 | src/switch/iswitch.c src/switch/ichannel.c src/switch/iparser.c \ 16 | src/switch/imap.c -o imap \ 17 | -ldriver -lbfsys -lbfutils -lbf_switchd_lib -lm 18 | 19 | server: src/iconfig.h src/server/common.h src/server/parser.c src/server/main.c 20 | cd src/server && make 21 | ln -sf src/server/build/imap-result-server . 22 | 23 | clean: 24 | -rm -f imap imap-result-server bf_drivers.log* zlog-cfg-cur 25 | 26 | .DEFAULT_GOAL := 27 | -------------------------------------------------------------------------------- /src/server/common.h: -------------------------------------------------------------------------------- 1 | #ifndef __COMMON_H__ 2 | #define __COMMON_H__ 3 | 4 | #include 5 | 6 | #define MAX_RX_QUEUE_PER_LCORE 16 7 | #define MAX_TX_QUEUE_PER_PORT 16 8 | 9 | struct lcore_queue_conf { 10 | unsigned n_rx_port; 11 | unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE]; 12 | //TODO: support multiple queues per core? 13 | unsigned rx_queue_id; 14 | } __rte_cache_aligned; 15 | 16 | #define RTE_LOGTYPE_IMAP RTE_LOGTYPE_USER1 17 | 18 | struct imap_result_meta { 19 | uint8_t resp_pkt_count; 20 | } __rte_packed; 21 | 22 | struct imap_probe_result { 23 | #if __PROBE_TYPE__ == PROBE_TYPE_SYN_PROBER 24 | uint16_t probe_port; 25 | uint8_t _pad; 26 | uint8_t result; 27 | #elif __PROBE_TYPE__ == PROBE_TYPE_ICMP_PROBER 28 | uint8_t icmp_type; 29 | uint8_t icmp_code; 30 | uint8_t _pad; 31 | uint8_t result; 32 | #endif 33 | } __rte_packed; 34 | 35 | struct imap_result_pack { 36 | uint32_t target[RESULTS_PER_RESULT_PACK]; 37 | struct imap_probe_result result[RESULTS_PER_RESULT_PACK]; 38 | } __rte_packed; 39 | 40 | struct imap_result_entry { 41 | uint32_t probe_addr; 42 | #if __PROBE_TYPE__ == PROBE_TYPE_SYN_PROBER 43 | uint16_t probe_port; 44 | #elif __PROBE_TYPE__ == PROBE_TYPE_ICMP_PROBER 45 | uint8_t icmp_type; 46 | uint8_t icmp_code; 47 | #endif 48 | uint32_t probe_result; 49 | }; 50 | 51 | #endif -------------------------------------------------------------------------------- /src/server/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright(c) 2010-2014 Intel Corporation 3 | 4 | # binary name 5 | APP = imap-result-server 6 | 7 | # all source are stored in SRCS-y 8 | SRCS-y := main.c parser.c 9 | 10 | # Build using pkg-config variables if possible 11 | ifneq ($(shell pkg-config --exists libdpdk && echo 0),0) 12 | $(error "no installation of DPDK found") 13 | endif 14 | 15 | all: shared 16 | .PHONY: shared static debug 17 | shared: build/$(APP)-shared 18 | ln -sf $(APP)-shared build/$(APP) 19 | static: build/$(APP)-static 20 | ln -sf $(APP)-static build/$(APP) 21 | debug: build/$(APP)-debug 22 | ln -sf $(APP)-debug build/$(APP) 23 | 24 | PKGCONF ?= pkg-config 25 | 26 | PC_FILE := $(shell $(PKGCONF) --path libdpdk 2>/dev/null) 27 | CFLAGS += -O3 $(shell $(PKGCONF) --cflags libdpdk) 28 | # Add flag to allow experimental API as l2fwd uses rte_ethdev_set_ptype API 29 | CFLAGS += -DALLOW_EXPERIMENTAL_API 30 | # remove this to disable logs 31 | # CFLAGS += -DDEBUG 32 | LDFLAGS_SHARED = $(shell $(PKGCONF) --libs libdpdk) 33 | LDFLAGS_SHARED += -lhiredis 34 | LDFLAGS_SHARED += -lpq 35 | LDFLAGS_STATIC = $(shell $(PKGCONF) --static --libs libdpdk) 36 | 37 | build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build 38 | $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED) 39 | 40 | build/$(APP)-static: $(SRCS-y) Makefile $(PC_FILE) | build 41 | $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_STATIC) 42 | 43 | build/$(APP)-debug: $(SRCS-y) Makefile $(PC_FILE) | build 44 | $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED) -DDEBUG 45 | 46 | build: 47 | @mkdir -p $@ 48 | 49 | run: 50 | sudo build/$(APP) -l 0 -n 1 -- -p 1 51 | 52 | .PHONY: clean 53 | clean: 54 | rm -rf build/$(APP) build/$(APP)-static build/$(APP)-shared 55 | test -d build && rm -rf build || true 56 | -------------------------------------------------------------------------------- /src/switch/ichannel.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: ichannel.c 3 | > Author: Guanyu Li 4 | > Mail: dracula.guanyu.li@gmail.com 5 | > Created Time: Mon 14 Dec 2020 10:23:02 AM CST 6 | > Description: Program about probe modules of IMap 7 | ************************************************************************/ 8 | 9 | #ifndef _ICHANNEL_H 10 | #define _ICHANNEL_H 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #define MAC_ARRAY(d, i) ((d >> ((5 - i) * 8)) & 0xff) 30 | #define IPV6_ARRAY(d, i) ((d >> ((3 - i)* 8)) & 0xff) 31 | 32 | typedef uint32_t ipaddr_n_t; // IPv4 address network order 33 | typedef uint32_t ipaddr_h_t; // IPv4 address host order 34 | typedef uint16_t port_n_t; // TCP/UDP port network order 35 | typedef uint16_t port_h_t; // TCP/UDP port host order 36 | 37 | // Pseudo header needed for checksum calculation 38 | struct psdhdr { 39 | ipaddr_h_t saddr; 40 | ipaddr_h_t daddr; 41 | uint8_t placeholder; 42 | uint8_t protocol; 43 | uint16_t tcp_length; 44 | struct tcphdr tcp; 45 | }; 46 | 47 | struct psdv6hdr { 48 | struct in6_addr saddr; 49 | struct in6_addr daddr; 50 | uint8_t placeholder; 51 | uint8_t protocol; 52 | uint16_t tcp_length; 53 | struct tcphdr tcp; 54 | }; 55 | 56 | typedef struct update_notifying_channel_s { 57 | int sockfd; 58 | char recvbuf[PKTBUF_SIZE]; 59 | uint8_t probe_table; 60 | uint16_t pipr_idx; 61 | uint16_t egress_port; 62 | } update_notifying_channel_t; 63 | 64 | #if __TOFINO_MODE__ == 0 65 | static const char CPUIF_NAME[] = "bf_pci0"; 66 | // static const char CPUIF_NAME[] = "enp4s0"; 67 | #else 68 | static const char CPUIF_NAME[] = "veth251"; 69 | #endif 70 | 71 | static unsigned short csum(unsigned short *ptr,int nbytes); 72 | int send_ipv6_syn_temp_to_switch(); 73 | int recv_ipv6_probe_report_from_switch(); 74 | int send_syn_temp_to_switch(); 75 | int send_icmp_temp_to_switch(); 76 | int recv_probe_report_from_switch(); 77 | int creat_update_notifying_channel(update_notifying_channel_t *channel); 78 | int recv_update_notification(update_notifying_channel_t *channel); 79 | int recv_update_notification_from_switch(uint32_t timer, uint8_t *pipr_filter); 80 | int send_flush_request_to_switch(); 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /src/iconfig.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: imap.h 3 | > Author: Guanyu Li 4 | > Mail: dracula.guanyu.li@gmail.com 5 | > Created Time: Mon 14 Dec 2020 10:23:02 AM CST 6 | > Description: Config and macro definition file for IMap 7 | ************************************************************************/ 8 | 9 | #ifndef _ICONFIG_H 10 | #define _ICONFIG_H 11 | 12 | #define __IP_TYPE__ 4 13 | #define __TOFINO_MODE__ 0 // 0: ASIC 1: Model 14 | 15 | #define PROBE_TYPE_SYN_PROBER 0 16 | #define PROBE_TYPE_ICMP_PROBER 1 17 | #define __PROBE_TYPE__ PROBE_TYPE_SYN_PROBER 18 | // #define __PROBE_TYPE__ PROBE_TYPE_ICMP_PROBER 19 | 20 | #define ETHER_TYPE_IRESULT 0x6666 21 | #define ETHER_TYPE_IREPORT 0x6668 22 | #define ETHER_TYPE_IFLUSH 0x6688 23 | #define ETHER_TYPE_ITEMPLATE 0x6888 24 | 25 | #define PROBE_RESULT_NO_RESP 0b00 26 | #define PROBE_RESULT_INACTIVE_RESP 0b01 27 | #define PROBE_RESULT_ACTIVE_RESP 0b10 28 | 29 | #define RESULT_PACKS_PER_PACKET 2 30 | #define RESULTS_PER_RESULT_PACK 8 31 | 32 | #define RESULT_ENTRY_BUF_SIZE (1 << 20) 33 | 34 | // Probe IP Range Index: Port Index + Per Port Index 35 | #define IP_RANGE_INDEX_BITS 16 36 | // Set IP_RANGE_INDEX_PORT_BITS = 0 is just for single-switch-port scanning 37 | // in Tsinghua network 38 | #define IP_RANGE_INDEX_PORT_BITS 0 39 | #define IP_RANGE_INDEX_PER_PORT_BITS \ 40 | (IP_RANGE_INDEX_BITS - IP_RANGE_INDEX_PORT_BITS) 41 | 42 | #define IP_RANGE_MAX_SIZE 512 43 | 44 | #define IP_RANGE_TABLE_SIZE (1 << IP_RANGE_INDEX_BITS) 45 | 46 | #define IP_PLACEHOLDER 0 47 | 48 | // Only for data plane 49 | #if __TOFINO_MODE__ == 0 50 | #define CPU_PORT 192 51 | #define RESULT_SERVER_PORT 144 52 | #else 53 | #define CPU_PORT 64 54 | #define RESULT_SERVER_PORT 3 55 | #endif 56 | 57 | #define RECIRC_PORT 196 58 | #define BROADCAST_MC_GID 255 59 | #define RESULT_SERVER_MC_GID 192 60 | #define UPDATE_NOTIFY_MIRROR_SID 66 61 | #define PKTBUF_SIZE 2048 62 | 63 | // #define RESULT_DATABASE_SIZE (RESULT_PACKS_PER_PACKET * RESULTS_PER_RESULT_PACK) 64 | // #define RESULT_DATABASE_SIZE_M1 (RESULT_DATABASE_SIZE - 1) 65 | #define RESULT_DATABASE_SIZE 16 66 | #define RESULT_DATABASE_SIZE_M1 15 67 | 68 | #if __IP_TYPE__ == 6 69 | #define PROBER_IPV6_P1 0xfe800000 70 | #define PROBER_IPV6_P2 0xfe800000 71 | #define PROBER_IPV6_P3 0x6a91d0ff 72 | #define PROBER_IPV6_P4 0xfe123456 73 | #else 74 | // #define PROBER_IP 0xc0a82801 75 | #define PROBER_IP 0xc0a82888 76 | #endif 77 | 78 | // #define PROBER_MAC 0x123456789abc 79 | #define PROBER_MAC 0x6891d0611258 80 | 81 | // Only for control plane 82 | #define PRIME_ROOT 3 83 | #define RANDOM_PICKER_SIZE (1 << 16) 84 | #define SLEEP_TIME_FOR_IDLE_CHANNEL 5 85 | 86 | // Only for result server 87 | #define MAX_PKT_BURST 10 88 | #define CHANNEL_MAX_LATENCY 500000000 //ns 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IMap 2 | 3 | ## Overview 4 | We identify the challenges that current network scanners meet, and propose IMap, a fast and scalable in-network scanner with programmable switches. 5 | 6 | IMap includes a probe packet generation module, which is responsible to generate high-speed probe packets with random address and adaptive rate, and a response packet processing module, which processes the response packets in a correct and efficient manner. 7 | 8 | To use IMap, operators should first specify the scanning address spaces and scanning port ranges beforehand. Then IMap control plane programs parse these configurations and issue the parsed parameters into the IMap packet processing logics. After that, IMap data plane programs generate high-speed probe packets and process the corresponding response packets accordingly. Finally, the scanning results, i.e., the information extracted from the response packets, are written into a persistent database, such as the Redis in-memory data store employed in this repo. The whole workflow of IMap is displayed as follow. 9 | 10 |
11 | 12 |
13 | 14 | ## Repository Structure 15 | `src`: The source code of IMap 16 | - `src/iconfig.h`: The usual configurations of IMap 17 | - `src/server`: The source code of backend agent running on the storage server 18 | - `src/switch`: The source code of IMap switch part including control plane and data plane 19 | - `src/switch/p4src`: The source code of IMap's data plane 20 | - `src/switch/*.h, *.c`: The source code of IMap's control plane 21 | 22 | 23 | ## Installation 24 | ### Deploy on the server with DPDK NIC 25 | ```sh 26 | # 0. Prepare the environment for compiling 27 | # Install the stable version of DPDK (we use dpdk-stable-20.11.1) and bind the 28 | # NIC connected to the switch with DPDK driver 29 | # 1. Install and start Redis 30 | sudo apt update && sudo apt install redis-server 31 | sudo systemctl start redis 32 | # 2. Download the source code of IMap 33 | git clone https://github.com/IMapScanner/IMap 34 | # 3. Compile IMap 35 | cd IMap 36 | make server 37 | ``` 38 | ### Deploy on the Barefoot Tofino switch 39 | ```sh 40 | # 0. Prepare the environment for compiling 41 | # Set the environment variable $SDE and $SDE_INSTALL, and download 42 | # the p4_build.sh from Barefoot and put it into $SDE. 43 | # 1. Download the source code of IMap 44 | git clone https://github.com/IMapScanner/IMap 45 | # 2. Configure and compile IMap 46 | cd IMap 47 | # Then modify src/iconfig.h according to your configuration and specify 48 | # the scanning address spaces and scanning port ranges in src/switch/imap.c 49 | make switch 50 | ``` 51 | 52 | ## Start the IMap scanner 53 | ### Start the IMap result server on the server 54 | ```sh 55 | sudo ./imap-result-server -l 0-7 -n 8 -- -p 1 56 | ``` 57 | ### Start the IMap scanner on the switch 58 | ```sh 59 | ./imap --probe-port-range 1:65535 --ip-list ip.txt --rate 55000000 60 | ``` 61 | -------------------------------------------------------------------------------- /src/switch/iparser.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: iparser.c 3 | > Author: Cheng Guo 4 | > Mail: aeromarisa@gmail.com 5 | > Created Time: Tue 29 Jun 2021 13:47:02 PM CST 6 | > Description: Config file parser for IMap 7 | ************************************************************************/ 8 | 9 | #include 10 | #include 11 | #include 12 | #include "iswitch.h" 13 | 14 | static int ip_space_list_parse(FILE *fd, long start_fptr, 15 | probe_entry_t **probe_ip_space, 16 | uint32_t *probe_ip_space_count) { 17 | char token1[256]; 18 | char token2[256]; 19 | *probe_ip_space_count = 0; 20 | 21 | fscanf(fd, "%s %s", token1, token2); 22 | if (strcmp(token1, "=") != 0 || strcmp(token2, "{") != 0) { 23 | printf("Invalid var defination format.\n"); 24 | return 1; 25 | } 26 | fscanf(fd, "%s", token1); 27 | while (1) { 28 | if (strcmp(token1, "}") != 0) { 29 | fscanf(fd, "%s %s", token2, token1); 30 | *probe_ip_space_count += 1; 31 | } 32 | else { 33 | // Go to start position of this var, and scan again 34 | fseek(fd, start_fptr, SEEK_SET); 35 | break; 36 | } 37 | } 38 | *probe_ip_space = (probe_entry_t *)malloc(*probe_ip_space_count * 39 | sizeof(probe_entry_t)); 40 | fscanf(fd, "%s %s", token1, token2); 41 | for (int entry_idx = 0; entry_idx < *probe_ip_space_count; entry_idx ++) { 42 | fscanf(fd, "%s %s", token1, token2); 43 | (*probe_ip_space)[entry_idx].start = htonl(inet_addr(token1)); 44 | (*probe_ip_space)[entry_idx].end = htonl(inet_addr(token2)); 45 | } 46 | fscanf(fd, "%s", token1); 47 | 48 | return 0; 49 | } 50 | 51 | void config_file_parse(const char *config_filename, 52 | probe_entry_t **probe_ip_space, 53 | uint32_t *probe_ip_space_count) { 54 | FILE *fd; 55 | 56 | printf("Start reading config file.\n"); 57 | fd = fopen(config_filename, "r"); 58 | if (fd == NULL) { 59 | // Error when opening config file 60 | printf("Error when opening config file!\n"); 61 | exit(0); 62 | } 63 | 64 | char var_name[256]; 65 | long start_fptr; 66 | int status; 67 | while (!feof(fd)) { 68 | fscanf(fd, "%s", var_name); 69 | if (feof(fd)) break; 70 | // Record start position of this config item 71 | start_fptr = ftell(fd); 72 | 73 | if (strcmp(var_name, "ip_space_list") == 0) { 74 | // Parse ip space list 75 | status = ip_space_list_parse(fd, start_fptr, 76 | probe_ip_space, 77 | probe_ip_space_count); 78 | } 79 | else { 80 | printf("Unrecognized config item: %s\n", var_name); 81 | } 82 | if (status != 0) { 83 | printf("Error when opening config file!\n"); 84 | exit(0); 85 | } 86 | } 87 | fclose(fd); 88 | printf("Config file read done.\n"); 89 | } -------------------------------------------------------------------------------- /src/switch/p4src/parser.p4: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: parser.p4 3 | > Author: Guanyu Li 4 | > Mail: dracula.guanyu.li@gmail.com 5 | > Created Time: Mon 14 Dec 2020 10:23:02 AM CST 6 | > Description: Parser declaration for data plane programs of IMap 7 | ************************************************************************/ 8 | 9 | #ifndef _PARSER_ 10 | #define _PARSER_ 11 | 12 | parser TofinoIngressParser( 13 | packet_in pkt, 14 | out ingress_intrinsic_metadata_t ig_intr_md) { 15 | state start { 16 | pkt.extract(ig_intr_md); 17 | transition select(ig_intr_md.resubmit_flag) { 18 | 1 : parse_resubmit; 19 | 0 : parse_port_metadata; 20 | } 21 | } 22 | 23 | state parse_resubmit { 24 | //pkt.extract(ig_md.resubmit_hdr); 25 | transition reject; 26 | } 27 | 28 | state parse_port_metadata { 29 | pkt.advance(PORT_METADATA_SIZE); 30 | transition accept; 31 | } 32 | } 33 | 34 | parser TofinoEgressParser( 35 | packet_in pkt, 36 | out egress_intrinsic_metadata_t eg_intr_md) { 37 | state start { 38 | pkt.extract(eg_intr_md); 39 | transition accept; 40 | } 41 | } 42 | 43 | // Empty egress parser/control blocks 44 | parser EmptyEgressParser( 45 | packet_in pkt, 46 | out H hdr, 47 | out M eg_md, 48 | out egress_intrinsic_metadata_t eg_intr_md) { 49 | state start { 50 | transition accept; 51 | } 52 | } 53 | 54 | parser StackParser(packet_in pkt, out custom_header_t hdr) { 55 | state start { // parse Ethernet 56 | pkt.extract(hdr.ethernet); 57 | transition select(hdr.ethernet.ether_type) { 58 | ETHERTYPE_ARP : parse_arp; 59 | ETHERTYPE_IPV4 : parse_ipv4; 60 | ETHERTYPE_IPV6 : parse_ipv6; 61 | default : reject; 62 | } 63 | } 64 | 65 | state parse_arp { 66 | pkt.extract(hdr.arp); 67 | transition select(hdr.arp.hw_type, hdr.arp.proto_type) { 68 | (0x0001, ETHERTYPE_IPV4) : parse_arp_ipv4; 69 | default : reject; 70 | } 71 | } 72 | 73 | state parse_arp_ipv4 { 74 | pkt.extract(hdr.arp_ipv4); 75 | transition accept; 76 | } 77 | 78 | state parse_ipv4 { 79 | pkt.extract(hdr.ipv4); 80 | transition select(hdr.ipv4.protocol) { 81 | IP_PROTOCOLS_ICMP : parse_icmp; 82 | IP_PROTOCOLS_TCP : parse_tcp; 83 | IP_PROTOCOLS_UDP : parse_udp; 84 | default : accept; 85 | } 86 | } 87 | 88 | state parse_ipv6 { 89 | pkt.extract(hdr.ipv6); 90 | transition select(hdr.ipv6.next_hdr) { 91 | IP_PROTOCOLS_ICMP : parse_icmp; 92 | IP_PROTOCOLS_TCP : parse_tcp; 93 | IP_PROTOCOLS_UDP : parse_udp; 94 | default : accept; 95 | } 96 | } 97 | 98 | state parse_icmp { 99 | pkt.extract(hdr.icmp); 100 | transition accept; 101 | } 102 | 103 | state parse_tcp { 104 | pkt.extract(hdr.tcp); 105 | transition accept; 106 | } 107 | 108 | state parse_udp { 109 | pkt.extract(hdr.udp); 110 | transition accept; 111 | } 112 | } 113 | 114 | parser ImapEgressParser(packet_in pkt, 115 | out custom_header_t hdr, 116 | out egress_metadata_t eg_md) { 117 | Checksum() icmp_csum; 118 | Checksum() tcp_csum; 119 | 120 | state start { 121 | internal_metadata_t internal_md = pkt.lookahead(); 122 | transition select(internal_md.pkt_label) { 123 | PKT_LABEL_UPDATE_NOTIFY: parse_mirror; 124 | default: parse_bridged; 125 | } 126 | } 127 | 128 | state parse_mirror { 129 | pkt.extract(eg_md.mirror); 130 | transition parse_ethernet; 131 | } 132 | 133 | state parse_bridged { 134 | pkt.extract(eg_md.bridged); 135 | transition parse_ethernet; 136 | } 137 | 138 | state parse_ethernet { 139 | pkt.extract(hdr.ethernet); 140 | eg_md.swp_mac = hdr.ethernet.src_mac; 141 | transition select(hdr.ethernet.ether_type) { 142 | ETHERTYPE_ARP : parse_arp; 143 | ETHERTYPE_IPV4 : parse_ipv4; 144 | ETHERTYPE_IPV6 : parse_ipv6; 145 | ETHERTYPE_ITEMPLATE : parse_ipv4; 146 | default : reject; 147 | } 148 | } 149 | 150 | state parse_arp { 151 | pkt.extract(hdr.arp); 152 | transition select(hdr.arp.hw_type, hdr.arp.proto_type) { 153 | (0x0001, ETHERTYPE_IPV4) : parse_arp_ipv4; 154 | default : reject; 155 | } 156 | } 157 | 158 | state parse_arp_ipv4 { 159 | pkt.extract(hdr.arp_ipv4); 160 | transition accept; 161 | } 162 | 163 | state parse_ipv4 { 164 | pkt.extract(hdr.ipv4); 165 | #if __IP_TYPE__ != 6 // Default IPv4 166 | eg_md.swp_ip = hdr.ipv4.src_ip; 167 | #endif 168 | tcp_csum.subtract({ hdr.ipv4.src_ip, hdr.ipv4.dst_ip }); 169 | transition select(hdr.ipv4.protocol) { 170 | IP_PROTOCOLS_ICMP : parse_icmp; 171 | IP_PROTOCOLS_TCP : parse_tcp; 172 | IP_PROTOCOLS_UDP : parse_udp; 173 | default : accept; 174 | } 175 | } 176 | 177 | state parse_ipv6 { 178 | pkt.extract(hdr.ipv6); 179 | #if __IP_TYPE__ == 6 180 | eg_md.swp_ip = hdr.ipv6.src_ip; 181 | #endif 182 | tcp_csum.subtract({ hdr.ipv6.src_ip, hdr.ipv6.dst_ip }); 183 | transition select(hdr.ipv6.next_hdr) { 184 | IP_PROTOCOLS_ICMP : parse_icmp; 185 | IP_PROTOCOLS_TCP : parse_tcp; 186 | IP_PROTOCOLS_UDP : parse_udp; 187 | default : accept; 188 | } 189 | } 190 | 191 | state parse_icmp { 192 | pkt.extract(hdr.icmp); 193 | icmp_csum.subtract({ hdr.icmp.checksum }); 194 | icmp_csum.subtract({ hdr.icmp.id, hdr.icmp.seq_no }); 195 | eg_md.icmp_csum = icmp_csum.get(); 196 | transition accept; 197 | } 198 | 199 | state parse_tcp { 200 | pkt.extract(hdr.tcp); 201 | eg_md.swp_port = hdr.tcp.src_port; 202 | eg_md.tmp_seq = hdr.tcp.seq_no; 203 | tcp_csum.subtract({ hdr.tcp.checksum }); 204 | tcp_csum.subtract({ 205 | hdr.tcp.src_port, hdr.tcp.dst_port, hdr.tcp.seq_no, hdr.tcp.ack_no, 206 | hdr.tcp.data_offset, hdr.tcp.res, hdr.tcp.urg, 207 | hdr.tcp.ack, hdr.tcp.psh, hdr.tcp.rst, hdr.tcp.syn, hdr.tcp.fin 208 | }); 209 | eg_md.tcp_csum = tcp_csum.get(); 210 | transition accept; 211 | } 212 | 213 | state parse_udp { 214 | pkt.extract(hdr.udp); 215 | transition accept; 216 | } 217 | } 218 | 219 | #endif /* _PARSER_ */ 220 | -------------------------------------------------------------------------------- /src/switch/p4src/header.p4: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: header.p4 3 | > Author: Guanyu Li 4 | > Mail: dracula.guanyu.li@gmail.com 5 | > Created Time: Mon 14 Dec 2020 10:23:02 AM CST 6 | > Description: Header declaration for data plane programs of IMap 7 | ************************************************************************/ 8 | 9 | #ifndef _HEADER_ 10 | #define _HEADER_ 11 | 12 | #include "../../iconfig.h" 13 | 14 | typedef bit<9> port_t; 15 | typedef bit<48> mac_addr_t; 16 | typedef bit<32> ipv4_addr_t; 17 | typedef bit<128> ipv6_addr_t; 18 | typedef bit<12> vlan_id_t; 19 | 20 | typedef bit ipr_idx_t; 21 | typedef bit ipr_idx_pidx_t; 22 | 23 | typedef bit<3> mirror_type_t; 24 | const mirror_type_t MIRROR_TYPE_I2E = 1; 25 | const mirror_type_t MIRROR_TYPE_E2E = 2; 26 | 27 | typedef bit<16> ether_type_t; 28 | const ether_type_t ETHERTYPE_ARP = 16w0x0806; 29 | const ether_type_t ETHERTYPE_IPV4 = 16w0x0800; 30 | const ether_type_t ETHERTYPE_IPV6 = 16w0x86dd; 31 | const ether_type_t ETHERTYPE_VLAN = 16w0x8100; 32 | 33 | const ether_type_t ETHERTYPE_IRESULT = ETHER_TYPE_IRESULT; 34 | const ether_type_t ETHERTYPE_IREPORT = ETHER_TYPE_IREPORT; 35 | const ether_type_t ETHERTYPE_IFLUSH = ETHER_TYPE_IFLUSH; 36 | const ether_type_t ETHERTYPE_ITEMPLATE = ETHER_TYPE_ITEMPLATE; 37 | 38 | typedef bit<8> ip_protocol_t; 39 | const ip_protocol_t IP_PROTOCOLS_ICMP = 1; 40 | const ip_protocol_t IP_PROTOCOLS_TCP = 6; 41 | const ip_protocol_t IP_PROTOCOLS_UDP = 17; 42 | 43 | const bit<16> ARP_OPCODE_REQUEST = 1; 44 | const bit<16> ARP_OPCODE_REPLY = 2; 45 | 46 | // 0: Normal packet 47 | // 1: Template packet 48 | // 2: Probe response packet (the target is active) 49 | // 3: Probe response packet (the target is inactive) 50 | // 4: Probe packets seed in Ingress or probe packet in Egress 51 | // 5: ARP request packet for PROBER_IP 52 | // 6: Flush request packet from the control plane 53 | // 7: Update notirication to the control plane 54 | typedef bit<8> pkt_label_t; 55 | const pkt_label_t PKT_LABEL_NORMAL = 0; 56 | const pkt_label_t PKT_LABEL_INACTIVE_RESP = 1; 57 | const pkt_label_t PKT_LABEL_ACTIVE_RESP = 2; 58 | const pkt_label_t PKT_LABEL_TEMPLATE = 3; 59 | const pkt_label_t PKT_LABEL_SEED = 4; 60 | const pkt_label_t PKT_LABEL_ARP_REQUEST = 5; 61 | const pkt_label_t PKT_LABEL_FLUSH_REQUEST = 6; 62 | const pkt_label_t PKT_LABEL_UPDATE_NOTIFY = 7; 63 | 64 | header ethernet_h { 65 | mac_addr_t dst_mac; 66 | mac_addr_t src_mac; 67 | bit<16> ether_type; 68 | } 69 | 70 | header vlan_tag_h { 71 | bit<3> pcp; 72 | bit<1> cfi; 73 | vlan_id_t vid; 74 | bit<16> ether_type; 75 | } 76 | 77 | header mpls_h { 78 | bit<20> label; 79 | bit<3> exp; 80 | bit<1> bos; 81 | bit<8> ttl; 82 | } 83 | 84 | header ipv4_h { 85 | bit<4> version; 86 | bit<4> ihl; 87 | bit<8> diffserv; 88 | bit<16> total_len; 89 | bit<16> identification; 90 | bit<3> flags; 91 | bit<13> frag_offset; 92 | bit<8> ttl; 93 | bit<8> protocol; 94 | bit<16> checksum; 95 | ipv4_addr_t src_ip; 96 | ipv4_addr_t dst_ip; 97 | } 98 | 99 | header ipv6_h { 100 | bit<4> version; 101 | bit<8> traffic_class; 102 | bit<20> flow_label; 103 | bit<16> payload_len; 104 | bit<8> next_hdr; 105 | bit<8> hop_limit; 106 | ipv6_addr_t src_ip; 107 | ipv6_addr_t dst_ip; 108 | } 109 | 110 | header icmp_h { 111 | bit<8> type; 112 | bit<8> code; 113 | bit<16> checksum; 114 | bit<16> id; 115 | bit<16> seq_no; 116 | // bit<64> tstamp; 117 | } 118 | 119 | header tcp_h { 120 | bit<16> src_port; 121 | bit<16> dst_port; 122 | bit<32> seq_no; 123 | bit<32> ack_no; 124 | bit<4> data_offset; 125 | bit<6> res; 126 | // Here we employ 6 byte flags 127 | // bit<6> flags; 128 | bit<1> urg; 129 | bit<1> ack; 130 | bit<1> psh; 131 | bit<1> rst; 132 | bit<1> syn; 133 | bit<1> fin; 134 | bit<16> window; 135 | bit<16> checksum; 136 | bit<16> urgent_ptr; 137 | } 138 | 139 | header udp_h { 140 | bit<16> src_port; 141 | bit<16> dst_port; 142 | bit<16> hdr_length; 143 | bit<16> checksum; 144 | } 145 | 146 | // Address Resolution Protocol -- RFC 6747 147 | header arp_h { 148 | bit<16> hw_type; 149 | bit<16> proto_type; 150 | bit<8> hw_addr_len; 151 | bit<8> proto_addr_len; 152 | bit<16> opcode; 153 | // ... 154 | } 155 | 156 | header arp_ipv4_h { 157 | mac_addr_t src_hw_addr; 158 | ipv4_addr_t src_proto_addr; 159 | mac_addr_t dst_hw_addr; 160 | ipv4_addr_t dst_proto_addr; 161 | } 162 | 163 | // Segment Routing Extension (SRH) -- IETFv7 164 | header ipv6_srh_h { 165 | bit<8> next_hdr; 166 | bit<8> hdr_ext_len; 167 | bit<8> routing_type; 168 | bit<8> seg_left; 169 | bit<8> last_entry; 170 | bit<8> flags; 171 | bit<16> tag; 172 | } 173 | 174 | // VXLAN -- RFC 7348 175 | header vxlan_h { 176 | bit<8> flags; 177 | bit<24> reserved; 178 | bit<24> vni; 179 | bit<8> reserved2; 180 | } 181 | 182 | // Generic Routing Encapsulation (GRE) -- RFC 1701 183 | header gre_h { 184 | bit<1> C; 185 | bit<1> R; 186 | bit<1> K; 187 | bit<1> S; 188 | bit<1> s; 189 | bit<3> recurse; 190 | bit<5> flags; 191 | bit<3> version; 192 | bit<16> proto; 193 | } 194 | 195 | header result_pack_h { 196 | bit<32> target_0; 197 | bit<32> target_1; 198 | bit<32> target_2; 199 | bit<32> target_3; 200 | bit<32> target_4; 201 | bit<32> target_5; 202 | bit<32> target_6; 203 | bit<32> target_7; 204 | bit<32> result_0; 205 | bit<32> result_1; 206 | bit<32> result_2; 207 | bit<32> result_3; 208 | bit<32> result_4; 209 | bit<32> result_5; 210 | bit<32> result_6; 211 | bit<32> result_7; 212 | } 213 | 214 | header result_meta_h { 215 | bit<8> resp_pkt_count; 216 | } 217 | 218 | struct result_h { 219 | result_meta_h result_meta; 220 | result_pack_h result_pack_0; 221 | result_pack_h result_pack_1; 222 | } 223 | 224 | header update_notification_h { 225 | bit<8> probe_table; 226 | ipr_idx_t pipr_idx; // Probe IP Range Index 227 | bit<7> _pad; // For aligning 228 | port_t egress_port; 229 | } 230 | 231 | #define INTERNAL_MD \ 232 | pkt_label_t pkt_label 233 | 234 | struct internal_metadata_t { 235 | INTERNAL_MD; 236 | } 237 | 238 | header bridged_h { 239 | // Indicate the imap packet type 240 | INTERNAL_MD; 241 | bit<8> resp_pkt_count; 242 | bit<16> probe_port_stride; 243 | bit<32> probe_result; 244 | } 245 | 246 | header mirror_h { 247 | INTERNAL_MD; 248 | bit<8> probe_table; 249 | ipr_idx_t pipr_idx; // Probe IP Range Index 250 | bit<7> _pad; // For aligning 251 | port_t egress_port; 252 | bit<16> probe_port_stride; 253 | } 254 | 255 | struct ingress_metadata_t { 256 | bridged_h bridged; 257 | #if __PROBE_TYPE__ == PROBE_TYPE_SYN_PROBER 258 | bit<16> probe_resp_port; 259 | bit<32> probe_resp_ack; 260 | #elif __PROBE_TYPE__ == PROBE_TYPE_ICMP_PROBER 261 | bit<16> probe_resp_id; 262 | bit<16> probe_resp_seq; 263 | #endif 264 | bit<32> last_probe_timer; 265 | } 266 | 267 | struct egress_metadata_t { 268 | bridged_h bridged; 269 | mirror_h mirror; 270 | update_notification_h update_notification; 271 | result_h result; 272 | bit<16> icmp_csum; 273 | bit<16> tcp_csum; 274 | bit<48> swp_mac; 275 | #if __IP_TYPE__ == 6 276 | ipv6_addr_t swp_ip; 277 | #else // Default IPv4 278 | ipv4_addr_t swp_ip; 279 | #endif 280 | bit<16> swp_port; 281 | bit<32> tmp_seq; 282 | bit<8> probe_table; 283 | ipr_idx_pidx_t pipr_border; 284 | ipr_idx_t pipr_idx; // Probe IP Range Index 285 | bit<32> pipr_end; 286 | MirrorId_t update_notification_mirror_sid; // Egress mirror session ID 287 | } 288 | 289 | struct custom_header_t { 290 | ethernet_h ethernet; 291 | arp_h arp; 292 | arp_ipv4_h arp_ipv4; 293 | ipv4_h ipv4; 294 | ipv6_h ipv6; 295 | icmp_h icmp; 296 | tcp_h tcp; 297 | udp_h udp; 298 | } 299 | 300 | struct probe_port_t { 301 | bit<16> pipr_switch_times; 302 | bit<16> probe_port; 303 | } 304 | 305 | #endif /* _HEADER_ */ 306 | -------------------------------------------------------------------------------- /src/server/main.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-3-Clause 2 | * Copyright(c) 2010-2016 Intel Corporation 3 | */ 4 | 5 | #include "../iconfig.h" 6 | #include "common.h" 7 | 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 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | void imap_main_loop(void); 47 | 48 | // static volatile bool force_quit; 49 | volatile bool force_quit; 50 | 51 | struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE]; 52 | 53 | // #define MAX_PKT_BURST 32 54 | #define MEMPOOL_CACHE_SIZE 256 55 | 56 | /* 57 | * Configurable number of RX/TX ring descriptors 58 | */ 59 | #define RTE_TEST_RX_DESC_DEFAULT 1024 60 | #define RTE_TEST_TX_DESC_DEFAULT 1024 61 | static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; 62 | static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; 63 | 64 | /* ethernet addresses of ports */ 65 | static struct rte_ether_addr imap_ports_eth_addr[RTE_MAX_ETHPORTS]; 66 | 67 | /* mask of enabled ports */ 68 | static uint32_t imap_enabled_port_mask = 1; 69 | 70 | static unsigned int imap_rx_queue_per_lcore = 1; 71 | 72 | static struct rte_eth_conf port_conf = { 73 | .rxmode = { 74 | .split_hdr_size = 0, 75 | }, 76 | .txmode = { 77 | .mq_mode = ETH_MQ_TX_NONE, 78 | }, 79 | }; 80 | 81 | struct rte_mempool * imap_pktmbuf_pool = NULL; 82 | 83 | static int 84 | imap_launch_one_lcore(__rte_unused void *dummy) 85 | { 86 | imap_main_loop(); 87 | return 0; 88 | } 89 | 90 | /* display usage */ 91 | static void 92 | imap_usage(const char *prgname) 93 | { 94 | printf("%s [EAL options] -- -p PORTMASK\n" 95 | " -p PORTMASK: hexadecimal bitmask of ports to configure\n", 96 | prgname); 97 | } 98 | 99 | static int 100 | imap_parse_portmask(const char *portmask) 101 | { 102 | char *end = NULL; 103 | unsigned long pm; 104 | 105 | /* parse hexadecimal string */ 106 | pm = strtoul(portmask, &end, 16); 107 | if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) 108 | return 0; 109 | 110 | return pm; 111 | } 112 | 113 | static unsigned int 114 | imap_parse_nqueue(const char *q_arg) 115 | { 116 | char *end = NULL; 117 | unsigned long n; 118 | 119 | /* parse hexadecimal string */ 120 | n = strtoul(q_arg, &end, 10); 121 | if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) 122 | return 0; 123 | if (n == 0) 124 | return 0; 125 | if (n >= MAX_RX_QUEUE_PER_LCORE) 126 | return 0; 127 | 128 | return n; 129 | } 130 | 131 | static const char short_options[] = 132 | "p:" /* portmask */ 133 | ; 134 | 135 | static const struct option lgopts[] = { 136 | {NULL, 0, 0, 0} 137 | }; 138 | 139 | /* Parse the argument given in the command line of the application */ 140 | static int 141 | imap_parse_args(int argc, char **argv) 142 | { 143 | int opt, ret, timer_secs; 144 | char **argvopt; 145 | int option_index; 146 | char *prgname = argv[0]; 147 | 148 | argvopt = argv; 149 | 150 | while ((opt = getopt_long(argc, argvopt, short_options, 151 | lgopts, &option_index)) != EOF) { 152 | 153 | switch (opt) { 154 | /* portmask */ 155 | case 'p': 156 | imap_enabled_port_mask = imap_parse_portmask(optarg); 157 | if (imap_enabled_port_mask == 0) { 158 | printf("invalid portmask\n"); 159 | imap_usage(prgname); 160 | return -1; 161 | } 162 | break; 163 | 164 | default: 165 | imap_usage(prgname); 166 | return -1; 167 | } 168 | } 169 | 170 | if (optind >= 0) 171 | argv[optind-1] = prgname; 172 | 173 | ret = optind-1; 174 | optind = 1; /* reset getopt lib */ 175 | return ret; 176 | } 177 | 178 | /* Check the link status of all ports in up to 9s, and print them finally */ 179 | static void 180 | check_all_ports_link_status(uint32_t port_mask) 181 | { 182 | #define CHECK_INTERVAL 100 /* 100ms */ 183 | #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ 184 | uint16_t portid; 185 | uint8_t count, all_ports_up, print_flag = 0; 186 | struct rte_eth_link link; 187 | int ret; 188 | char link_status_text[RTE_ETH_LINK_MAX_STR_LEN]; 189 | 190 | printf("\nChecking link status"); 191 | fflush(stdout); 192 | for (count = 0; count <= MAX_CHECK_TIME; count++) { 193 | if (force_quit) 194 | return; 195 | all_ports_up = 1; 196 | RTE_ETH_FOREACH_DEV(portid) { 197 | if (force_quit) 198 | return; 199 | if ((port_mask & (1 << portid)) == 0) 200 | continue; 201 | memset(&link, 0, sizeof(link)); 202 | ret = rte_eth_link_get_nowait(portid, &link); 203 | if (ret < 0) { 204 | all_ports_up = 0; 205 | if (print_flag == 1) 206 | printf("Port %u link get failed: %s\n", 207 | portid, rte_strerror(-ret)); 208 | continue; 209 | } 210 | /* print link status if flag set */ 211 | if (print_flag == 1) { 212 | rte_eth_link_to_str(link_status_text, 213 | sizeof(link_status_text), &link); 214 | printf("Port %d %s\n", portid, 215 | link_status_text); 216 | continue; 217 | } 218 | /* clear all_ports_up flag if any link down */ 219 | if (link.link_status == ETH_LINK_DOWN) { 220 | all_ports_up = 0; 221 | break; 222 | } 223 | } 224 | /* after finally printing all link status, get out */ 225 | if (print_flag == 1) 226 | break; 227 | 228 | if (all_ports_up == 0) { 229 | printf("."); 230 | fflush(stdout); 231 | rte_delay_ms(CHECK_INTERVAL); 232 | } 233 | 234 | /* set the print_flag if all ports up or timeout */ 235 | if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { 236 | print_flag = 1; 237 | printf("done\n"); 238 | } 239 | } 240 | } 241 | 242 | static void 243 | signal_handler(int signum) 244 | { 245 | if (signum == SIGINT || signum == SIGTERM) { 246 | printf("\n\nSignal %d received, preparing to exit...\n", 247 | signum); 248 | force_quit = true; 249 | } 250 | } 251 | 252 | int 253 | main(int argc, char **argv) 254 | { 255 | struct lcore_queue_conf *qconf; 256 | int ret; 257 | uint16_t nb_ports; 258 | uint16_t nb_ports_available = 0; 259 | uint16_t portid, last_port; 260 | unsigned lcore_id, rx_lcore_id; 261 | unsigned nb_ports_in_mask = 0; 262 | unsigned int nb_lcores = 0; 263 | unsigned int nb_mbufs; 264 | int i; 265 | 266 | /* init EAL */ 267 | ret = rte_eal_init(argc, argv); 268 | if (ret < 0) 269 | rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n"); 270 | argc -= ret; 271 | argv += ret; 272 | 273 | force_quit = false; 274 | signal(SIGINT, signal_handler); 275 | signal(SIGTERM, signal_handler); 276 | 277 | /* parse application arguments (after the EAL ones) */ 278 | ret = imap_parse_args(argc, argv); 279 | if (ret < 0) 280 | rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n"); 281 | 282 | /* convert to number of cycles */ 283 | // timer_period *= rte_get_timer_hz(); 284 | 285 | nb_ports = rte_eth_dev_count_avail(); 286 | if (nb_ports == 0) 287 | rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n"); 288 | 289 | /* check port mask to possible port mask */ 290 | if (imap_enabled_port_mask & ~((1 << nb_ports) - 1)) 291 | rte_exit(EXIT_FAILURE, "Invalid portmask; possible (0x%x)\n", 292 | (1 << nb_ports) - 1); 293 | 294 | /* Initialize the port/queue configuration of each logical core */ 295 | RTE_ETH_FOREACH_DEV(portid) { 296 | /* skip ports that are not enabled */ 297 | if ((imap_enabled_port_mask & (1 << portid)) == 0) 298 | continue; 299 | 300 | /* add 1 queue on every lcore */ 301 | for (rx_lcore_id = 0; rx_lcore_id < RTE_MAX_LCORE; rx_lcore_id++) { 302 | 303 | /* get the lcore_id for this port */ 304 | if (rte_lcore_is_enabled(rx_lcore_id) == 0 || 305 | lcore_queue_conf[rx_lcore_id].n_rx_port == 306 | imap_rx_queue_per_lcore) { 307 | continue; 308 | } 309 | 310 | qconf = &lcore_queue_conf[rx_lcore_id]; 311 | qconf->rx_port_list[qconf->n_rx_port] = portid; 312 | qconf->n_rx_port++; 313 | qconf->rx_queue_id = nb_lcores; // nb_lcores act as queue id 314 | printf("Lcore %u: RX port %u Queue id %u\n", rx_lcore_id, 315 | portid, nb_lcores); 316 | nb_lcores++; 317 | } 318 | } 319 | 320 | nb_mbufs = RTE_MAX(nb_ports * (nb_rxd + nb_txd + MAX_PKT_BURST + 321 | nb_lcores * MEMPOOL_CACHE_SIZE), 8192U); 322 | 323 | /* create the mbuf pool */ 324 | imap_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", nb_mbufs, 325 | MEMPOOL_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, 326 | rte_socket_id()); 327 | if (imap_pktmbuf_pool == NULL) 328 | rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n"); 329 | 330 | /* Initialise each port */ 331 | RTE_ETH_FOREACH_DEV(portid) { 332 | struct rte_eth_rxconf rxq_conf; 333 | // struct rte_eth_txconf txq_conf; 334 | struct rte_eth_conf local_port_conf = port_conf; 335 | struct rte_eth_dev_info dev_info; 336 | 337 | /* skip ports that are not enabled */ 338 | if ((imap_enabled_port_mask & (1 << portid)) == 0) { 339 | printf("Skipping disabled port %u\n", portid); 340 | continue; 341 | } 342 | nb_ports_available++; 343 | 344 | /* init port */ 345 | printf("Initializing port %u... ", portid); 346 | fflush(stdout); 347 | 348 | ret = rte_eth_dev_info_get(portid, &dev_info); 349 | if (ret != 0) 350 | rte_exit(EXIT_FAILURE, 351 | "Error during getting device (port %u) info: %s\n", 352 | portid, strerror(-ret)); 353 | 354 | ret = rte_eth_dev_configure(portid, nb_lcores, 0, &local_port_conf); 355 | if (ret < 0) 356 | rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n", 357 | ret, portid); 358 | 359 | ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd, &nb_txd); 360 | if (ret < 0) 361 | rte_exit(EXIT_FAILURE, 362 | "Cannot adjust number of descriptors: err=%d, port=%u\n", 363 | ret, portid); 364 | 365 | ret = rte_eth_macaddr_get(portid, 366 | &imap_ports_eth_addr[portid]); 367 | if (ret < 0) 368 | rte_exit(EXIT_FAILURE, 369 | "Cannot get MAC address: err=%d, port=%u\n", 370 | ret, portid); 371 | 372 | /* init RX queues */ 373 | fflush(stdout); 374 | rxq_conf = dev_info.default_rxconf; 375 | rxq_conf.offloads = local_port_conf.rxmode.offloads; 376 | for (i = 0; i < nb_lcores; i++) { 377 | ret = rte_eth_rx_queue_setup(portid, i, nb_rxd, 378 | rte_eth_dev_socket_id(portid), 379 | &rxq_conf, 380 | imap_pktmbuf_pool); 381 | if (ret < 0) 382 | rte_exit(EXIT_FAILURE, 383 | "rte_eth_rx_queue_setup:err=%d, port=%u\n", 384 | ret, portid); 385 | } 386 | 387 | 388 | /* Start device */ 389 | ret = rte_eth_dev_start(portid); 390 | if (ret < 0) 391 | rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n", 392 | ret, portid); 393 | 394 | printf("done: \n"); 395 | 396 | ret = rte_eth_promiscuous_enable(portid); 397 | if (ret != 0) 398 | rte_exit(EXIT_FAILURE, 399 | "rte_eth_promiscuous_enable:err=%s, port=%u\n", 400 | rte_strerror(-ret), portid); 401 | 402 | printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n", 403 | portid, 404 | imap_ports_eth_addr[portid].addr_bytes[0], 405 | imap_ports_eth_addr[portid].addr_bytes[1], 406 | imap_ports_eth_addr[portid].addr_bytes[2], 407 | imap_ports_eth_addr[portid].addr_bytes[3], 408 | imap_ports_eth_addr[portid].addr_bytes[4], 409 | imap_ports_eth_addr[portid].addr_bytes[5]); 410 | 411 | /* initialize port stats */ 412 | // memset(&port_statistics, 0, sizeof(port_statistics)); 413 | } 414 | 415 | if (!nb_ports_available) { 416 | rte_exit(EXIT_FAILURE, 417 | "All available ports are disabled. Please set portmask.\n"); 418 | } 419 | 420 | check_all_ports_link_status(imap_enabled_port_mask); 421 | 422 | ret = 0; 423 | /* launch per-lcore init on every lcore */ 424 | rte_eal_mp_remote_launch(imap_launch_one_lcore, NULL, CALL_MAIN); 425 | RTE_LCORE_FOREACH_WORKER(lcore_id) { 426 | if (rte_eal_wait_lcore(lcore_id) < 0) { 427 | ret = -1; 428 | break; 429 | } 430 | } 431 | 432 | RTE_ETH_FOREACH_DEV(portid) { 433 | if ((imap_enabled_port_mask & (1 << portid)) == 0) 434 | continue; 435 | printf("Closing port %d...", portid); 436 | ret = rte_eth_dev_stop(portid); 437 | if (ret != 0) 438 | printf("rte_eth_dev_stop: err=%d, port=%d\n", 439 | ret, portid); 440 | rte_eth_dev_close(portid); 441 | printf(" Done\n"); 442 | } 443 | printf("Bye...\n"); 444 | 445 | return ret; 446 | } 447 | -------------------------------------------------------------------------------- /src/switch/iswitch.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: iswitch.h 3 | > Author: Guanyu Li 4 | > Mail: dracula.guanyu.li@gmail.com 5 | > Created Time: Mon 14 Dec 2020 10:23:02 AM CST 6 | > Description: Barefoot switch control interfaces for IMap 7 | ************************************************************************/ 8 | 9 | #ifndef _ISWITCH_H 10 | #define _ISWITCH_H 11 | 12 | #include 13 | #include 14 | #include 15 | // #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" 25 | #define MAC_DATA(d) *((uint8_t *)&d + 5), *((uint8_t *)&d + 4), \ 26 | *((uint8_t *)&d + 3), *((uint8_t *)&d + 2), \ 27 | *((uint8_t *)&d + 1), *((uint8_t *)&d + 0) 28 | 29 | typedef struct forward_table_info_s { 30 | // Key field ids 31 | bf_rt_id_t kid_dst_mac; 32 | // Action Ids 33 | bf_rt_id_t aid_unicast; 34 | bf_rt_id_t aid_broadcast; 35 | bf_rt_id_t aid_drop; 36 | // Data field Ids for ai_unicast 37 | bf_rt_id_t did_port; 38 | // Key and Data objects 39 | bf_rt_table_key_hdl *key; 40 | bf_rt_table_data_hdl *data; 41 | // Multicast info 42 | bf_mc_session_hdl_t mc_session; 43 | bf_mc_mgrp_hdl_t mc_mgrp; 44 | bf_mc_node_hdl_t mc_node; 45 | bf_mc_port_map_t mc_port_map; 46 | bf_mc_lag_map_t mc_lag_map; 47 | } forward_table_info_t; 48 | 49 | typedef struct forward_table_entry_s { 50 | // Key value 51 | uint64_t dst_mac; 52 | // Match length (for LPM) 53 | uint16_t match_length; 54 | // Action 55 | char action[16]; 56 | // Data value 57 | bf_dev_port_t egress_port; 58 | } forward_table_entry_t; 59 | 60 | typedef struct probe_resp_handler_table_info_s { 61 | // Key field ids 62 | bf_rt_id_t kid_resp_pkt_count; 63 | // Action Ids 64 | bf_rt_id_t aid_report_to_result_server; 65 | // Key and Data objects 66 | bf_rt_table_key_hdl *key; 67 | bf_rt_table_data_hdl *data; 68 | } probe_resp_handler_table_info_t; 69 | 70 | typedef struct probe_resp_handler_table_entry_s { 71 | // Key value 72 | uint64_t resp_pkt_count; 73 | } probe_resp_handler_table_entry_t; 74 | 75 | typedef struct editor_table_info_s { 76 | // Key field ids 77 | bf_rt_id_t kid_egress_port; 78 | // Action Ids 79 | bf_rt_id_t aid_editor; 80 | // Data field Ids for ai_unicast 81 | bf_rt_id_t did_dst_mac; 82 | bf_rt_id_t did_pipr_sidx; // Probe IP Range Start Index 83 | // Key and Data objects 84 | bf_rt_table_key_hdl *key; 85 | bf_rt_table_data_hdl *data; 86 | } editor_table_info_t; 87 | 88 | typedef struct editor_table_entry_s { 89 | // Key value 90 | bf_dev_port_t egress_port; 91 | // Data value 92 | uint64_t dst_mac; 93 | uint32_t pipr_sidx; 94 | } editor_table_entry_t; 95 | 96 | typedef struct resultdb_table_info_s { 97 | // Key field ids 98 | bf_rt_id_t kid_resp_pkt_count; 99 | 100 | // Action Ids 101 | bf_rt_id_t aid_update_resultdb; 102 | 103 | // Key and Data objects 104 | bf_rt_table_key_hdl *key; 105 | bf_rt_table_data_hdl *data; 106 | } resultdb_table_info_t; 107 | 108 | typedef struct resultdb_table_entry_s { 109 | // Key value 110 | uint64_t resp_pkt_count; 111 | } resultdb_table_entry_t; 112 | 113 | typedef struct register_info_s { 114 | // Key field ids 115 | bf_rt_id_t kid_register_index; 116 | // Data field Ids for register table 117 | bf_rt_id_t did_value; 118 | // Key and Data objects 119 | bf_rt_table_key_hdl *key; 120 | bf_rt_table_data_hdl *data; 121 | } register_info_t; 122 | 123 | typedef struct register_entry_s { 124 | // Key value 125 | uint32_t register_index; 126 | // Data value 127 | uint32_t value; 128 | uint32_t value_array_size; 129 | uint64_t *value_array; 130 | } register_entry_t; 131 | 132 | typedef struct probe_period_s { 133 | const bf_rt_table_hdl *reg; 134 | register_info_t reg_info; 135 | register_entry_t entry; 136 | } probe_period_t; 137 | 138 | typedef struct probe_port_stride_s { 139 | const bf_rt_table_hdl *reg; 140 | register_info_t reg_info; 141 | register_entry_t entry; 142 | } probe_port_stride_t; 143 | 144 | typedef struct probe_port_s { 145 | const bf_rt_table_hdl *reg; 146 | register_info_t reg_info; 147 | register_entry_t entry; 148 | } probe_port_t; 149 | 150 | typedef struct probe_ip_range_table_s { 151 | const bf_rt_table_hdl *pipr_start_reg; 152 | const bf_rt_table_hdl *pipr_end_reg; 153 | const bf_rt_table_hdl *pipr_pidx_reg; 154 | #if __IP_TYPE__ == 6 155 | const bf_rt_table_hdl *pip_prefix_1_reg; 156 | const bf_rt_table_hdl *pip_prefix_2_reg; 157 | const bf_rt_table_hdl *pip_prefix_3_reg; 158 | #endif 159 | register_info_t pipr_start_reg_info; 160 | register_info_t pipr_end_reg_info; 161 | register_info_t pipr_pidx_reg_info; 162 | #if __IP_TYPE__ == 6 163 | register_info_t pip_prefix_1_reg_info; 164 | register_info_t pip_prefix_2_reg_info; 165 | register_info_t pip_prefix_3_reg_info; 166 | #endif 167 | } probe_ip_range_table_t; 168 | 169 | // typedef struct iswitch_info_s { 170 | // bf_status_t status; 171 | // bf_rt_target_t dev_tgt; 172 | // bf_switchd_context_t *switchd_ctx; 173 | // const bf_rt_info_hdl *bfrt_info; 174 | // const bf_rt_table_hdl *forward_table; 175 | // const bf_rt_table_hdl *editor_table; 176 | // bf_rt_session_hdl *session; 177 | // forward_table_info_t forward_table_info; 178 | // editor_table_info_t editor_table_info; 179 | // } iswitch_info_t; 180 | 181 | typedef struct switch_port_s { 182 | uint64_t dst_mac; 183 | char fp_port[5]; 184 | } switch_port_t; 185 | 186 | typedef struct probe_entry_s { 187 | uint32_t start; 188 | uint32_t end; 189 | } probe_entry_t; 190 | 191 | typedef struct iswitch_s { 192 | bf_rt_target_t dev_tgt; 193 | bf_rt_session_hdl *session; 194 | probe_period_t period_reg; 195 | probe_port_stride_t stride_reg; 196 | probe_port_t port_reg; 197 | probe_ip_range_table_t pipr_table_t0; 198 | probe_ip_range_table_t pipr_table_t1; 199 | } iswitch_t; 200 | 201 | static void switchd_setup(bf_switchd_context_t *switchd_ctx); 202 | static void bfrt_setup(const bf_rt_target_t *dev_tgt, 203 | const bf_rt_info_hdl **bfrt_info, 204 | bf_rt_session_hdl **session); 205 | static void port_setup(const bf_rt_target_t *dev_tgt, 206 | const switch_port_t *port_list, 207 | const uint8_t rule_count); 208 | static void result_server_port_setup(const bf_rt_target_t *dev_tgt, 209 | const bf_dev_port_t result_server_port); 210 | static void result_server_multicast_setup(const bf_rt_target_t *dev_tgt, 211 | const bf_rt_info_hdl *bfrt_info); 212 | static void update_notifying_mirror_setup(const bf_rt_target_t *dev_tgt); 213 | static void forward_table_setup(const bf_rt_target_t *dev_tgt, 214 | const bf_rt_info_hdl *bfrt_info, 215 | const bf_rt_table_hdl **fwd_table, 216 | forward_table_info_t *fwd_table_info, 217 | const switch_port_t *forward_list, 218 | const uint8_t rule_count); 219 | static void forward_table_entry_add(const bf_rt_target_t *dev_tgt, 220 | const bf_rt_session_hdl *session, 221 | const bf_rt_table_hdl *fwd_table, 222 | forward_table_info_t *fwd_table_info, 223 | forward_table_entry_t *fwd_entry); 224 | static void forward_table_deploy(const bf_rt_target_t *dev_tgt, 225 | const bf_rt_info_hdl *bfrt_info, 226 | const bf_rt_session_hdl *session, 227 | const switch_port_t *forward_list, 228 | const uint8_t rule_count); 229 | static void probe_resp_active_handler_table_setup( 230 | const bf_rt_info_hdl *bfrt_info, 231 | const bf_rt_table_hdl **handler_table, 232 | probe_resp_handler_table_info_t *handler_table_info); 233 | static void probe_resp_inactive_handler_table_setup( 234 | const bf_rt_info_hdl *bfrt_info, 235 | const bf_rt_table_hdl **handler_table, 236 | probe_resp_handler_table_info_t *handler_table_info); 237 | static void probe_resp_handler_table_entry_add( 238 | const bf_rt_target_t *dev_tgt, 239 | const bf_rt_session_hdl *session, 240 | const bf_rt_table_hdl *handler_table, 241 | probe_resp_handler_table_info_t *handler_table_info, 242 | probe_resp_handler_table_entry_t *handler_entry); 243 | static void probe_resp_handler_table_deploy(const bf_rt_target_t *dev_tgt, 244 | const bf_rt_info_hdl *bfrt_info, 245 | const bf_rt_session_hdl *session); 246 | static void editor_table_setup(const bf_rt_info_hdl *bfrt_info, 247 | const bf_rt_table_hdl **edtr_table, 248 | editor_table_info_t *edtr_table_info); 249 | static void editor_table_entry_add(const bf_rt_target_t *dev_tgt, 250 | const bf_rt_session_hdl *session, 251 | const bf_rt_table_hdl *edtr_table, 252 | editor_table_info_t *edtr_table_info, 253 | editor_table_entry_t *edtr_entry); 254 | static void editor_table_deploy(const bf_rt_target_t *dev_tgt, 255 | const bf_rt_info_hdl *bfrt_info, 256 | const bf_rt_session_hdl *session, 257 | const switch_port_t *forward_list, 258 | const uint8_t rule_count); 259 | static void resultdb_table_setup(const bf_rt_info_hdl *bfrt_info, 260 | uint32_t resultdb_idx, 261 | const bf_rt_table_hdl **target_table, 262 | const bf_rt_table_hdl **result_table, 263 | resultdb_table_info_t *target_table_info, 264 | resultdb_table_info_t *result_table_info); 265 | static void resultdb_table_entry_add(const bf_rt_target_t *dev_tgt, 266 | const bf_rt_session_hdl *session, 267 | uint32_t resultdb_idx, 268 | const bf_rt_table_hdl *resultdb_table, 269 | resultdb_table_info_t *resultdb_table_info, 270 | resultdb_table_entry_t *resultdb_entry); 271 | static void resultdb_table_deploy(const bf_rt_target_t *dev_tgt, 272 | const bf_rt_info_hdl *bfrt_info, 273 | const bf_rt_session_hdl *session); 274 | static void register_setup(const bf_rt_info_hdl *bfrt_info, 275 | const char *reg_name, 276 | const char *value_field_name, 277 | const bf_rt_table_hdl **reg, 278 | register_info_t *reg_info); 279 | static void register_write(const bf_rt_target_t *dev_tgt, 280 | const bf_rt_session_hdl *session, 281 | const bf_rt_table_hdl *reg, 282 | register_info_t *reg_info, 283 | register_entry_t *reg_entry); 284 | static void register_write_no_wait(const bf_rt_target_t *dev_tgt, 285 | const bf_rt_session_hdl *session, 286 | const bf_rt_table_hdl *reg, 287 | register_info_t *reg_info, 288 | register_entry_t *reg_entry); 289 | static void register_read(const bf_rt_target_t *dev_tgt, 290 | const bf_rt_session_hdl *session, 291 | const bf_rt_table_hdl *reg, 292 | register_info_t *reg_info, 293 | register_entry_t *reg_entry); 294 | static void probe_period_setup(const bf_rt_info_hdl *bfrt_info, 295 | probe_period_t *period_reg); 296 | void probe_period_config(iswitch_t *iswitch, uint32_t probe_period); 297 | static void probe_port_stride_setup(const bf_rt_info_hdl *bfrt_info, 298 | probe_port_stride_t *stride_reg); 299 | void probe_port_stride_config(iswitch_t *iswitch, uint16_t probe_port_stride); 300 | static void probe_port_setup(const bf_rt_info_hdl *bfrt_info, 301 | probe_port_t *port_reg); 302 | void probe_port_config(iswitch_t *iswitch, uint16_t probe_port); 303 | static void probe_ip_range_table_setup(const bf_rt_info_hdl *bfrt_info, 304 | probe_ip_range_table_t *pipr_table_t0, 305 | probe_ip_range_table_t *pipr_table_t1); 306 | void probe_ip_range_table_reset(iswitch_t *iswitch, const uint8_t probe_table); 307 | void probe_ip_range_table_install(iswitch_t *iswitch, 308 | const uint8_t probe_table, 309 | const uint32_t pipr_idx, 310 | const probe_entry_t *probe_entry); 311 | void probe_ip_range_table_install_batch(iswitch_t *iswitch, 312 | const uint8_t probe_table, 313 | const uint32_t pipr_idx_start, 314 | const uint32_t batch_size, 315 | const probe_entry_t *probe_entries); 316 | // void probe_ip_range_table_fetch(iswitch_t *iswitch, 317 | // const uint8_t probe_table, 318 | // const uint32_t pipr_idx); 319 | int launch_iswitch(iswitch_t *iswitch, 320 | const switch_port_t *forward_list, 321 | const uint8_t rule_count); 322 | 323 | #endif 324 | -------------------------------------------------------------------------------- /src/server/parser.c: -------------------------------------------------------------------------------- 1 | #include "../iconfig.h" 2 | #include "common.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #define REDIS_MODE 0 27 | #define POSTGRE_MODE 1 28 | 29 | // #define DATABASE_MODE REDIS_MODE 30 | #define DATABASE_MODE POSTGRE_MODE 31 | 32 | #if DATABASE_MODE == POSTGRE_MODE 33 | #include 34 | static void exit_nicely(PGconn *conn) { 35 | PQfinish(conn); 36 | exit(1); 37 | } 38 | #elif DATABASE_MODE == REDIS_MODE 39 | #include 40 | #endif 41 | 42 | extern volatile bool force_quit; 43 | extern struct lcore_queue_conf lcore_queue_conf[]; 44 | 45 | #ifdef DEBUG 46 | #define NUM_ENTRIES (RESULT_ENTRY_BUF_SIZE / sizeof(struct imap_result_entry)) 47 | struct imap_result_entry result_buf[NUM_ENTRIES]; 48 | size_t result_buf_cnt = 0; 49 | #endif 50 | 51 | void 52 | print_ethaddr(const char *msg, unsigned char * eth_addr) { 53 | printf("%s: ", msg); 54 | printf("%2x:%2x:%2x:%2x:%2x:%2x\n", eth_addr[0], eth_addr[1], eth_addr[2], 55 | eth_addr[3], eth_addr[4], eth_addr[5]); 56 | } 57 | 58 | const char* 59 | probe_result_display(uint8_t probe_result) { 60 | switch (probe_result) { 61 | case PROBE_RESULT_INACTIVE_RESP: 62 | return "inactive"; 63 | case PROBE_RESULT_ACTIVE_RESP: 64 | return "active"; 65 | }; 66 | } 67 | 68 | const char* 69 | icmp_type_display(uint8_t icmp_type) { 70 | switch (icmp_type) { 71 | case ICMP_ECHOREPLY: 72 | return "Echo Reply"; 73 | case ICMP_DEST_UNREACH: 74 | return "Destination Unreachable"; 75 | case ICMP_SOURCE_QUENCH: 76 | return "Source Quench"; 77 | case ICMP_REDIRECT: 78 | return "Redirect (change route)"; 79 | case ICMP_ECHO: 80 | return "Echo Request"; 81 | case ICMP_TIME_EXCEEDED: 82 | return "Time Exceeded"; 83 | case ICMP_PARAMETERPROB: 84 | return "Parameter Problem"; 85 | case ICMP_TIMESTAMP: 86 | return "Timestamp Request"; 87 | case ICMP_TIMESTAMPREPLY: 88 | return "Timestamp Reply"; 89 | case ICMP_INFO_REQUEST: 90 | return "Information Request"; 91 | case ICMP_INFO_REPLY: 92 | return "Information Reply"; 93 | case ICMP_ADDRESS: 94 | return "Address Mask Request"; 95 | case ICMP_ADDRESSREPLY: 96 | return "Address Mask Reply"; 97 | }; 98 | return "Unsupported ICMP Type"; 99 | } 100 | 101 | const char* 102 | icmp_code_display(uint8_t icmp_type, uint8_t icmp_code) { 103 | if (icmp_type == ICMP_ECHOREPLY) { 104 | return "OK"; 105 | } 106 | else if (icmp_type == ICMP_DEST_UNREACH) { 107 | switch (icmp_code) { 108 | case ICMP_NET_UNREACH: 109 | return "Network Unreachable"; 110 | case ICMP_HOST_UNREACH: 111 | return "Host Unreachable"; 112 | case ICMP_PROT_UNREACH: 113 | return "Protocol Unreachable"; 114 | case ICMP_PORT_UNREACH: 115 | return "Port Unreachable"; 116 | case ICMP_FRAG_NEEDED: 117 | return "Fragmentation Needed/DF set"; 118 | case ICMP_SR_FAILED: 119 | return "Source Route failed"; 120 | case ICMP_PKT_FILTERED: 121 | return "Packet filtered"; 122 | case ICMP_PREC_VIOLATION: 123 | return "Precedence violation"; 124 | case ICMP_PREC_CUTOFF: 125 | return "Precedence cut off"; 126 | }; 127 | } 128 | else if (icmp_type == ICMP_REDIRECT) { 129 | switch (icmp_code) { 130 | case ICMP_REDIR_NET: 131 | return "Redirect Net"; 132 | case ICMP_REDIR_HOST: 133 | return "Redirect Host"; 134 | case ICMP_REDIR_NETTOS: 135 | return "Redirect Net for TOS"; 136 | case ICMP_REDIR_HOSTTOS: 137 | return "Redirect Host for TOS"; 138 | }; 139 | } 140 | else if (icmp_type == ICMP_TIME_EXCEEDED) { 141 | switch (icmp_code) { 142 | case ICMP_EXC_TTL: 143 | return "TTL count exceeded"; 144 | case ICMP_EXC_FRAGTIME: 145 | return "Fragment Reass time exceeded"; 146 | }; 147 | } 148 | return "Unsupported ICMP Code"; 149 | } 150 | 151 | void 152 | print_imap_result_entry(const char *msg, struct imap_result_entry entry) { 153 | printf("%s: ", msg); 154 | uint8_t *ip_addr = (uint8_t *)&entry.probe_addr; 155 | #if __PROBE_TYPE__ == PROBE_TYPE_SYN_PROBER 156 | printf("%3u.%3u.%3u.%3u:%5hu\t", 157 | ip_addr[0], ip_addr[1], ip_addr[2], ip_addr[3], entry.probe_port); 158 | printf("%s\n", probe_result_display(entry.probe_result)); 159 | #elif __PROBE_TYPE__ == PROBE_TYPE_ICMP_PROBER 160 | printf("%3u.%3u.%3u.%3u\t", ip_addr[0], ip_addr[1], ip_addr[2], ip_addr[3]); 161 | printf("%s\t", probe_result_display(entry.probe_result)); 162 | printf("%s\t%s\n", 163 | icmp_type_display(entry.icmp_type), 164 | icmp_code_display(entry.icmp_type, entry.icmp_code)); 165 | #endif 166 | } 167 | 168 | void 169 | imap_main_loop(void) 170 | { 171 | struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; 172 | unsigned lcore_id; 173 | unsigned i, j, m, n, idx, portid, nb_rx; 174 | struct lcore_queue_conf *qconf; 175 | struct rte_eth_dev_tx_buffer *buffer; 176 | unsigned count; 177 | 178 | lcore_id = rte_lcore_id(); 179 | qconf = &lcore_queue_conf[lcore_id]; 180 | #if DATABASE_MODE == POSTGRE_MODE 181 | const char *conninfo; 182 | PGconn *conn; 183 | conninfo = "host=127.0.0.1 port=5432 dbname=imap user=postgres"; 184 | conn = PQconnectdb(conninfo); 185 | if (PQstatus(conn) != CONNECTION_OK) { 186 | printf("Connection to database failed: %s\n", 187 | PQerrorMessage(conn)); 188 | exit_nicely(conn); 189 | } 190 | else { 191 | printf("Database connected.\n"); 192 | } 193 | PGresult *res; 194 | char command_buffer[256]; 195 | #elif DATABASE_MODE == REDIS_MODE 196 | 197 | redisContext *redis_conn; 198 | redisReply *redis_reply; 199 | redis_conn = redisConnect("127.0.0.1", 6379); 200 | if (redis_conn->err) { 201 | rte_exit(EXIT_FAILURE, 202 | "Redis connection error: %s\n", redis_conn->errstr); 203 | } 204 | else { 205 | RTE_LOG(INFO, IMAP, "Redis database connected\n"); 206 | } 207 | #endif 208 | 209 | if (qconf->n_rx_port == 0) { 210 | RTE_LOG(INFO, IMAP, "lcore %u has nothing to do\n", lcore_id); 211 | return; 212 | } 213 | 214 | RTE_LOG(INFO, IMAP, "entering main loop on lcore %u\n", lcore_id); 215 | 216 | for (i = 0; i < qconf->n_rx_port; i++) { 217 | 218 | portid = qconf->rx_port_list[i]; 219 | RTE_LOG(INFO, IMAP, " -- lcoreid=%u portid=%u\n", lcore_id, 220 | portid); 221 | 222 | } 223 | 224 | count = 0; 225 | 226 | while (!force_quit) { 227 | /* 228 | * Read packet from RX queues 229 | */ 230 | for (i = 0; i < qconf->n_rx_port; i++) { 231 | 232 | portid = qconf->rx_port_list[i]; 233 | nb_rx = rte_eth_rx_burst(portid, qconf->rx_queue_id, 234 | pkts_burst, MAX_PKT_BURST); 235 | 236 | if (unlikely(nb_rx == 0)) { 237 | continue; 238 | } 239 | 240 | for (j = 0; j < nb_rx; j++) { 241 | /* extract ethernet */ 242 | struct rte_ether_hdr *eth_hdr; 243 | eth_hdr = rte_pktmbuf_mtod(pkts_burst[j], void *); 244 | rte_prefetch0(eth_hdr); 245 | 246 | if (eth_hdr->ether_type == \ 247 | rte_be_to_cpu_16(ETHER_TYPE_IRESULT)) { 248 | /* extract result packs */ 249 | struct imap_result_meta *meta = (struct imap_result_meta *) 250 | ((char*)eth_hdr + sizeof(struct rte_ether_hdr)); 251 | struct imap_result_pack *packs = (struct imap_result_pack *) 252 | ((char*)meta + sizeof(struct imap_result_meta)); 253 | if (meta->resp_pkt_count != \ 254 | RESULT_PACKS_PER_PACKET * RESULTS_PER_RESULT_PACK) { 255 | count += meta->resp_pkt_count; 256 | #ifdef DEBUG 257 | printf("This is a result packet after flushing " 258 | "(resp_pkt_count: %u, sum_count: %u)\n", 259 | meta->resp_pkt_count, count); 260 | #endif 261 | for (idx = 0; idx < meta->resp_pkt_count; idx++) { 262 | m = idx / RESULTS_PER_RESULT_PACK; 263 | n = idx % RESULTS_PER_RESULT_PACK; 264 | #ifdef DEBUG 265 | result_buf[result_buf_cnt].probe_addr = \ 266 | packs[m].target[n]; 267 | #if __PROBE_TYPE__ == PROBE_TYPE_SYN_PROBER 268 | result_buf[result_buf_cnt].probe_port = \ 269 | rte_be_to_cpu_16(packs[m].result[n].probe_port); 270 | #elif __PROBE_TYPE__ == PROBE_TYPE_ICMP_PROBER 271 | result_buf[result_buf_cnt].icmp_type = \ 272 | packs[m].result[n].icmp_type; 273 | result_buf[result_buf_cnt].icmp_code = \ 274 | packs[m].result[n].icmp_code; 275 | #endif 276 | result_buf[result_buf_cnt].probe_result = \ 277 | packs[m].result[n].result; 278 | print_imap_result_entry("data entry", 279 | result_buf[result_buf_cnt]); 280 | result_buf_cnt += 1; 281 | #endif 282 | #if DATABASE_MODE == POSTGRE_MODE 283 | #if __PROBE_TYPE__ == PROBE_TYPE_SYN_PROBER 284 | sprintf(command_buffer, 285 | "INSERT INTO imap VALUES ('%u.%u.%u.%u:%u', %u) ON CONFLICT DO NOTHING", 286 | ((uint8_t *)&(packs[m].target[n]))[0], 287 | ((uint8_t *)&(packs[m].target[n]))[1], 288 | ((uint8_t *)&(packs[m].target[n]))[2], 289 | ((uint8_t *)&(packs[m].target[n]))[3], 290 | rte_be_to_cpu_16(packs[m].result[n].probe_port), 291 | packs[m].result[n].result); 292 | #elif __PROBE_TYPE__ == PROBE_TYPE_ICMP_PROBER 293 | sprintf(command_buffer, 294 | "INSERT INTO imap VALUES ('%u.%u.%u.%u', %u)", 295 | ((uint8_t *)&(packs[m].target[n]))[0], 296 | ((uint8_t *)&(packs[m].target[n]))[1], 297 | ((uint8_t *)&(packs[m].target[n]))[2], 298 | ((uint8_t *)&(packs[m].target[n]))[3], 299 | packs[m].result[n].result); 300 | #endif 301 | res = PQexec(conn, command_buffer); 302 | if (PQresultStatus(res)!=PGRES_COMMAND_OK) { 303 | printf("insert failed: %s\n", PQerrorMessage(conn)); 304 | } 305 | // PQclear(res); 306 | #elif DATABASE_MODE == REDIS_MODE 307 | #if __PROBE_TYPE__ == PROBE_TYPE_SYN_PROBER 308 | redis_reply = redisCommand( 309 | redis_conn, "set %u.%u.%u.%u:%hu %s", 310 | ((uint8_t *)&(packs[m].target[n]))[0], 311 | ((uint8_t *)&(packs[m].target[n]))[1], 312 | ((uint8_t *)&(packs[m].target[n]))[2], 313 | ((uint8_t *)&(packs[m].target[n]))[3], 314 | rte_be_to_cpu_16(packs[m].result[n].probe_port), 315 | probe_result_display(packs[m].result[n].result) 316 | ); 317 | #elif __PROBE_TYPE__ == PROBE_TYPE_ICMP_PROBER 318 | redis_reply = redisCommand( 319 | redis_conn, "set %u.%u.%u.%u %s", 320 | ((uint8_t *)&(packs[m].target[n]))[0], 321 | ((uint8_t *)&(packs[m].target[n]))[1], 322 | ((uint8_t *)&(packs[m].target[n]))[2], 323 | ((uint8_t *)&(packs[m].target[n]))[3], 324 | probe_result_display(packs[m].result[n].result) 325 | ); 326 | #endif 327 | if (redis_reply->type == REDIS_REPLY_ERROR) { 328 | rte_exit(EXIT_FAILURE, 329 | "Redis insertion error: %s\n", 330 | redis_reply->str); 331 | } 332 | #endif 333 | } 334 | } 335 | else { 336 | count += RESULT_PACKS_PER_PACKET * \ 337 | RESULTS_PER_RESULT_PACK; 338 | #ifdef DEBUG 339 | printf("This is a result packet after evicting " 340 | "(sum_count: %u)\n", count); 341 | #endif 342 | for (m = 0; m < RESULT_PACKS_PER_PACKET; m++) { 343 | for (n = 0; n < RESULTS_PER_RESULT_PACK; n++) { 344 | #ifdef DEBUG 345 | result_buf[result_buf_cnt].probe_addr = \ 346 | packs[m].target[n]; 347 | #if __PROBE_TYPE__ == PROBE_TYPE_SYN_PROBER 348 | result_buf[result_buf_cnt].probe_port = \ 349 | rte_be_to_cpu_16(packs[m].result[n].probe_port); 350 | #elif __PROBE_TYPE__ == PROBE_TYPE_ICMP_PROBER 351 | result_buf[result_buf_cnt].icmp_type = \ 352 | packs[m].result[n].icmp_type; 353 | result_buf[result_buf_cnt].icmp_code = \ 354 | packs[m].result[n].icmp_code; 355 | #endif 356 | result_buf[result_buf_cnt].probe_result = \ 357 | packs[m].result[n].result; 358 | print_imap_result_entry("data entry", 359 | result_buf[result_buf_cnt]); 360 | result_buf_cnt += 1; 361 | #endif 362 | #if DATABASE_MODE == POSTGRE_MODE 363 | #if __PROBE_TYPE__ == PROBE_TYPE_SYN_PROBER 364 | sprintf(command_buffer, 365 | "INSERT INTO imap VALUES ('%u.%u.%u.%u:%u', %u) ON CONFLICT DO NOTHING", 366 | ((uint8_t *)&(packs[m].target[n]))[0], 367 | ((uint8_t *)&(packs[m].target[n]))[1], 368 | ((uint8_t *)&(packs[m].target[n]))[2], 369 | ((uint8_t *)&(packs[m].target[n]))[3], 370 | rte_be_to_cpu_16(packs[m].result[n].probe_port), 371 | packs[m].result[n].result); 372 | #elif __PROBE_TYPE__ == PROBE_TYPE_ICMP_PROBER 373 | sprintf(command_buffer, 374 | "INSERT INTO imap VALUES ('%u.%u.%u.%u', %u)", 375 | ((uint8_t *)&(packs[m].target[n]))[0], 376 | ((uint8_t *)&(packs[m].target[n]))[1], 377 | ((uint8_t *)&(packs[m].target[n]))[2], 378 | ((uint8_t *)&(packs[m].target[n]))[3], 379 | packs[m].result[n].result); 380 | #endif 381 | res = PQexec(conn, command_buffer); 382 | if (PQresultStatus(res)!=PGRES_COMMAND_OK) { 383 | printf("insert failed: %s\n", PQerrorMessage(conn)); 384 | } 385 | // PQclear(res); 386 | 387 | #elif DATABASE_MODE == REDIS_MODE 388 | #if __PROBE_TYPE__ == PROBE_TYPE_SYN_PROBER 389 | redis_reply = redisCommand( 390 | redis_conn, "set %u.%u.%u.%u:%hu %s", 391 | ((uint8_t *)&(packs[m].target[n]))[0], 392 | ((uint8_t *)&(packs[m].target[n]))[1], 393 | ((uint8_t *)&(packs[m].target[n]))[2], 394 | ((uint8_t *)&(packs[m].target[n]))[3], 395 | rte_be_to_cpu_16( 396 | packs[m].result[n].probe_port), 397 | probe_result_display( 398 | packs[m].result[n].result) 399 | ); 400 | #elif __PROBE_TYPE__ == PROBE_TYPE_ICMP_PROBER 401 | redis_reply = redisCommand( 402 | redis_conn, "set %u.%u.%u.%u %s", 403 | ((uint8_t *)&(packs[m].target[n]))[0], 404 | ((uint8_t *)&(packs[m].target[n]))[1], 405 | ((uint8_t *)&(packs[m].target[n]))[2], 406 | ((uint8_t *)&(packs[m].target[n]))[3], 407 | probe_result_display( 408 | packs[m].result[n].result) 409 | ); 410 | #endif 411 | if (redis_reply->type == REDIS_REPLY_ERROR) { 412 | rte_exit(EXIT_FAILURE, 413 | "Redis insertion error: %s\n", 414 | redis_reply->str); 415 | } 416 | #endif 417 | } 418 | } 419 | } 420 | 421 | #ifdef DEBUG 422 | if (result_buf_cnt >= NUM_ENTRIES) { 423 | // TODO: call data buf handler 424 | } 425 | #endif 426 | } 427 | rte_pktmbuf_free(pkts_burst[j]); 428 | } 429 | } 430 | } 431 | } 432 | -------------------------------------------------------------------------------- /src/switch/imap.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: imap.c 3 | > Author: Guanyu Li 4 | > Mail: dracula.guanyu.li@gmail.com 5 | > Created Time: Mon 14 Dec 2020 10:23:02 AM CST 6 | > Description: Main program of IMap 7 | ************************************************************************/ 8 | 9 | #include "../iconfig.h" 10 | #include "imap.h" 11 | #include "iswitch.h" 12 | #include "ichannel.h" 13 | #include "iparser.h" 14 | 15 | typedef struct imap_conf_s { 16 | int log_level; 17 | uint32_t probe_period; 18 | uint32_t waiting_time; 19 | port_h_t probe_port; 20 | probe_entry_t probe_port_range; 21 | char config_filename[256]; 22 | } imap_conf_t; 23 | 24 | const switch_port_t FORWARD_LIST[] = { 25 | {0x6891d061b4c4, "1/0"}, 26 | // {0x6891d061124b, "4/0"}, 27 | }; 28 | 29 | // PRIME_LIST[i] is the smallest prime greater than 2 ^ i 30 | const uint32_t PRIME_LIST [] = { 31 | // 1, 2, 4, 8, 16, 32, 64, 128, ( 2 ^ i) 32 | 2, 3, 5, 11, 17, 37, 67, 131, 33 | // 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 34 | 257, 521, 1031, 2053, 4099, 8209, 16411, 32771, 35 | // 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 36 | 65537, 131101, 262147, 524309, 1048583, 2097169, 4194319, 8388617, 37 | // 16777216, 33554432, 67108864, 134217728, 268435456, 536870912 38 | 16777259, 33554467, 67108879, 134217757, 268435459, 536870923 39 | }; 40 | 41 | probe_entry_t PIPR_ENTRIES[((uint64_t)1 << 32) / IP_RANGE_MAX_SIZE]; 42 | uint64_t PIPR_ENTRY_COUNT; 43 | 44 | static void parse_options(imap_conf_t *iconf, int argc, char **argv) { 45 | int option_index = 0; 46 | enum opts { 47 | OPT_LOG_LEVEL = 1, 48 | OPT_PROBE_PORT, 49 | OPT_PROBE_PORT_RANGE, 50 | OPT_RATE, 51 | OPT_SEED_RATE, 52 | OPT_WAITING_TIME, 53 | OPT_CONFIG_FILE, 54 | }; 55 | static struct option options[] = { 56 | {"help", no_argument, 0, 'h'}, 57 | {"log-level", optional_argument, 0, OPT_LOG_LEVEL}, 58 | {"probe-port", required_argument, 0, OPT_PROBE_PORT}, 59 | {"probe-port-range", required_argument, 0, OPT_PROBE_PORT_RANGE}, 60 | {"rate", required_argument, 0, OPT_RATE}, 61 | {"seed-rate", required_argument, 0, OPT_SEED_RATE}, 62 | {"waiting-time", required_argument, 0, OPT_WAITING_TIME}, 63 | {"ip-list", required_argument, 0, OPT_CONFIG_FILE}, 64 | }; 65 | 66 | memset(iconf, 0, sizeof(imap_conf_t)); 67 | iconf->probe_period = 1000000000; // Default set to 1s (10^9 ns) 68 | iconf->waiting_time = 0xffffffff; 69 | 70 | while (1) { 71 | int c = getopt_long(argc, argv, "h", options, &option_index); 72 | 73 | if (c == -1) { 74 | break; 75 | } 76 | switch (c) { 77 | case OPT_LOG_LEVEL: 78 | iconf->log_level = atoi(optarg); 79 | printf("Log Level: %d\n", iconf->log_level); 80 | break; 81 | case OPT_PROBE_PORT: 82 | iconf->probe_port = atoi(optarg); 83 | printf("Probe Port : %hu\n", iconf->probe_port); 84 | break; 85 | case OPT_PROBE_PORT_RANGE: 86 | if (sscanf(optarg, "%hu:%hu", \ 87 | &(iconf->probe_port_range.start), \ 88 | &(iconf->probe_port_range.end)) != 2) { 89 | printf("Invalid format for --probe-port-range\n"); 90 | exit(0); 91 | } 92 | else { 93 | printf("Probe Port Range: %hu:%hu\n", 94 | iconf->probe_port_range.start, 95 | iconf->probe_port_range.end); 96 | } 97 | break; 98 | case OPT_RATE: 99 | iconf->probe_period /= atoi(optarg); 100 | iconf->probe_period *= ARRLEN(FORWARD_LIST); 101 | printf("Rate: %u (Probe period: %u)\n", 102 | atoi(optarg), iconf->probe_period); 103 | break; 104 | case OPT_SEED_RATE: 105 | iconf->probe_period /= atoi(optarg); 106 | printf("Probe seed rate: %d (Probe period: %d)\n", 107 | atoi(optarg), iconf->probe_period); 108 | break; 109 | case OPT_WAITING_TIME: 110 | iconf->waiting_time = atoi(optarg); 111 | printf("Waiting time: %u\n", atoi(optarg)); 112 | break; 113 | case OPT_CONFIG_FILE: 114 | strcpy(iconf->config_filename, optarg); 115 | printf("IP list config file: %s\n", optarg); 116 | break; 117 | case 'h': 118 | case '?': 119 | printf("imap \n"); 120 | printf("Usage : imap --rate/seed-rate / " 121 | "--waiting-time " 122 | "--probe-port / " 123 | "--probe-port-range \n"); 124 | exit(c == 'h' ? 0 : 1); 125 | break; 126 | default: 127 | printf("Invalid option\n"); 128 | exit(0); 129 | break; 130 | } 131 | } 132 | 133 | if (iconf->probe_port_range.end == 0) { 134 | if (iconf->probe_port == 0) { 135 | printf("ERROR: Probe port or probe port range " 136 | "must be specified correctly\n"); 137 | exit(0); 138 | } 139 | else { 140 | iconf->probe_port_range.start = iconf->probe_port; 141 | iconf->probe_port_range.end = iconf->probe_port; 142 | } 143 | } 144 | 145 | if (iconf->probe_period * (uint64_t)IP_RANGE_TABLE_SIZE \ 146 | * IP_RANGE_MAX_SIZE < CHANNEL_MAX_LATENCY) { 147 | printf("ERROR: Probe rate is too fast, it must be set to be smaller " 148 | "than IP_RANGE_TABLE_SIZE * IP_RANGE_MAX_SIZE * 10^9 / " 149 | "CHANNEL_MAX_LATENCY to avoid race conditions\n"); 150 | exit(0); 151 | } 152 | } 153 | 154 | static void start_scanner(imap_conf_t *iconf, 155 | iswitch_t *iswitch, 156 | const probe_entry_t *probe_space, 157 | const uint32_t probe_entry_count) { 158 | int imap_status = 0; 159 | uint16_t port_range_size = 0; 160 | uint64_t probe_space_size = 0; 161 | uint32_t entry_size = 0; 162 | uint8_t entry_size_base; 163 | probe_entry_t pipr_entry; 164 | update_notifying_channel_t update_channel; 165 | struct timespec start_time, current_time; 166 | // Next are only used when the probe space is greater 167 | // than IP_RANGE_TABLE_SIZE 168 | uint64_t rest_probe_space_size; 169 | uint32_t *rest_size = NULL; 170 | uint32_t *prime_base = NULL; 171 | uint32_t *prime_count = NULL; 172 | uint32_t *random_picker = NULL; 173 | uint32_t picker_cursor = 0; // Random picker cursor 174 | uint32_t picker_coverage = 0; // Random picker coverage 175 | uint32_t entry_idx = 0; 176 | uint64_t pipr_entry_idx = 0; 177 | uint8_t not_completed = 0; 178 | uint32_t batch_size = 0; 179 | 180 | port_range_size = iconf->probe_port_range.end - \ 181 | iconf->probe_port_range.start + 1; 182 | 183 | printf("Probe port range size: %hu\n", port_range_size); 184 | 185 | for (uint32_t idx = 0; idx < probe_entry_count; idx++) { 186 | probe_space_size += probe_space[idx].end - probe_space[idx].start + 1; 187 | } 188 | 189 | printf("Probe space size: %lu\n", probe_space_size); 190 | 191 | // Default we employ the pipr_t0 first. 192 | probe_ip_range_table_reset(iswitch, 0); 193 | 194 | rest_probe_space_size = probe_space_size; 195 | rest_size = (uint32_t *)malloc(probe_entry_count * sizeof(uint32_t)); 196 | prime_base = (uint32_t *)malloc(probe_entry_count * sizeof(uint32_t)); 197 | prime_count = (uint32_t *)malloc(probe_entry_count * sizeof(uint32_t)); 198 | random_picker = (uint32_t *)malloc 199 | (RANDOM_PICKER_SIZE * sizeof(uint32_t)); 200 | 201 | entry_size = (uint32_t)ceil(1.0 * probe_space_size / IP_RANGE_TABLE_SIZE); 202 | memset(random_picker, 0, RANDOM_PICKER_SIZE * sizeof(uint32_t)); 203 | // Resize the entry_size to 2 ^ i 204 | entry_size = pow(2, (uint32_t)ceil(log2(entry_size))); 205 | // Control the maxmium entry size 206 | entry_size = (entry_size <= IP_RANGE_MAX_SIZE) ? entry_size : \ 207 | IP_RANGE_MAX_SIZE; 208 | printf("Probe IP range table entry size: %u\n", entry_size); 209 | entry_size_base = (uint8_t)log2(entry_size); 210 | // Prepare for the data structure to allocate entries for pipr table 211 | for (uint32_t idx = 0; idx < probe_entry_count; idx++) { 212 | rest_size[idx] = probe_space[idx].end - probe_space[idx].start + 1; 213 | // Prepare for the prime base 214 | prime_base[idx] = (uint32_t)ceil(1.0 * rest_size[idx] / entry_size); 215 | prime_base[idx] = (uint32_t)ceil(log2(prime_base[idx])); 216 | prime_count[idx] = 0; 217 | // Construct the random picker 218 | // (random picker is used to implement the weighted random number 219 | // generation, utilizing the storage to gain efficient computing) 220 | picker_coverage = (uint32_t)(1.0 * rest_size[idx] / 221 | probe_space_size * RANDOM_PICKER_SIZE); 222 | for (uint32_t offset = 0; offset < picker_coverage; offset++) { 223 | random_picker[picker_cursor] = idx; 224 | picker_cursor += 1; 225 | } 226 | } 227 | // Employ "multiplicative group of integers modulo n" to compute entries 228 | PIPR_ENTRY_COUNT = 0; 229 | while (rest_probe_space_size != 0) { 230 | // Select a nonempty probe space entry 231 | do { 232 | // Here we use the instead of RANDOM_PICKER_SIZE, because the real 233 | // size (picker_cursor) may be smaller than RANDOM_PICKER_SIZE 234 | entry_idx = random_picker[rand() % picker_cursor]; 235 | // printf("Debug - entry_idx: %u\n", entry_idx); 236 | } while (rest_size[entry_idx] == 0); 237 | // Generate a valid address range (pipr entry) with the method in ZMap 238 | do { 239 | // printf("Debug - prime_count: %u\n", prime_count[entry_idx]); 240 | pipr_entry.start = probe_space[entry_idx].start; 241 | // printf("Debug - start base: 0x%x\n", pipr_entry.start); 242 | pipr_entry.start += ((prime_count[entry_idx] * PRIME_ROOT) % \ 243 | PRIME_LIST[prime_base[entry_idx]] 244 | ) << entry_size_base; 245 | // printf("Debug - start: 0x%x\n", pipr_entry.start); 246 | prime_count[entry_idx] += 1; 247 | } while (pipr_entry.start > probe_space[entry_idx].end); 248 | pipr_entry.end = pipr_entry.start + (entry_size - 1); 249 | if (pipr_entry.end > probe_space[entry_idx].end) { 250 | pipr_entry.end = probe_space[entry_idx].end; 251 | } 252 | // Store the generated pipr entry 253 | PIPR_ENTRIES[PIPR_ENTRY_COUNT] = pipr_entry; 254 | PIPR_ENTRY_COUNT += 1; 255 | // Update the rest probe space 256 | rest_size[entry_idx] -= pipr_entry.end - pipr_entry.start + 1; 257 | rest_probe_space_size -= pipr_entry.end - pipr_entry.start + 1; 258 | } 259 | printf("Entry count of probe ip range table: %lu\n", PIPR_ENTRY_COUNT); 260 | 261 | // NOTICE: sleep is used to avoid race condition for control channel! 262 | printf("Waiting %u seconds to avoid race condition " 263 | "in control channel\n", SLEEP_TIME_FOR_IDLE_CHANNEL); 264 | sleep(SLEEP_TIME_FOR_IDLE_CHANNEL); 265 | 266 | // Install probe ip range entry to t0 267 | clock_gettime(CLOCK_REALTIME, &start_time); 268 | if (PIPR_ENTRY_COUNT - pipr_entry_idx < IP_RANGE_TABLE_SIZE) { 269 | // The pipr table can not be loaded fully this time 270 | batch_size = PIPR_ENTRY_COUNT - pipr_entry_idx; 271 | // We add an extra entry in the last slot to ensure the correctness 272 | pipr_entry.start = IP_PLACEHOLDER; 273 | pipr_entry.end = pipr_entry.start + (entry_size - 1); 274 | probe_ip_range_table_install(iswitch, 0, 275 | IP_RANGE_TABLE_SIZE - 1, &pipr_entry); 276 | } 277 | else { 278 | batch_size = IP_RANGE_TABLE_SIZE; 279 | } 280 | // printf("Debug: batch_size %u\n", batch_size); 281 | // Default we employ the pipr_t0 first. 282 | probe_ip_range_table_install_batch(iswitch, 0, 0, batch_size, 283 | &PIPR_ENTRIES[pipr_entry_idx]); 284 | pipr_entry_idx += batch_size; 285 | not_completed += 1; 286 | printf("Debug: %lu probe ip range entries are left for port %hu\n", 287 | PIPR_ENTRY_COUNT - pipr_entry_idx, 288 | iconf->probe_port_range.end - port_range_size + 1); 289 | if (pipr_entry_idx == PIPR_ENTRY_COUNT) { 290 | // The pipr entries are all loaded 291 | if (port_range_size != 0) { 292 | // The current port is probed, considering the next probe port in 293 | // the range 294 | port_range_size -= 1; 295 | } 296 | if (port_range_size != 0) { 297 | // The whole port range is probed 298 | pipr_entry_idx = 0; 299 | } 300 | } 301 | clock_gettime(CLOCK_REALTIME, ¤t_time); 302 | printf("Debug: Install probe ip range entries into t0 within %f seconds\n", 303 | ((current_time.tv_sec - start_time.tv_sec) * 1000000000.0 + \ 304 | current_time.tv_nsec - start_time.tv_nsec) / 1000000000.0); 305 | 306 | if (!(pipr_entry_idx == PIPR_ENTRY_COUNT && port_range_size == 0)) { 307 | // Install probe ip range entry to t1 308 | clock_gettime(CLOCK_REALTIME, &start_time); 309 | if (PIPR_ENTRY_COUNT - pipr_entry_idx < IP_RANGE_TABLE_SIZE) { 310 | // The pipr table can not be loaded fully this time 311 | batch_size = PIPR_ENTRY_COUNT - pipr_entry_idx; 312 | // We add an extra entry in the last slot to ensure the correctness 313 | pipr_entry.start = IP_PLACEHOLDER; 314 | pipr_entry.end = pipr_entry.start + (entry_size - 1); 315 | probe_ip_range_table_install(iswitch, 1, 316 | IP_RANGE_TABLE_SIZE - 1, &pipr_entry); 317 | } 318 | else { 319 | batch_size = IP_RANGE_TABLE_SIZE; 320 | } 321 | probe_ip_range_table_install_batch(iswitch, 1, 0, batch_size, 322 | &PIPR_ENTRIES[pipr_entry_idx]); 323 | pipr_entry_idx += batch_size; 324 | not_completed += 1; 325 | printf("Debug: %lu probe ip range entries are left for port %hu\n", 326 | PIPR_ENTRY_COUNT - pipr_entry_idx, 327 | iconf->probe_port_range.end - port_range_size + 1); 328 | if (pipr_entry_idx == PIPR_ENTRY_COUNT) { 329 | // The pipr entries are all loaded 330 | if (port_range_size != 0) { 331 | // The current port is probed, considering the next probe port 332 | // in the range 333 | port_range_size -= 1; 334 | } 335 | if (port_range_size != 0) { 336 | // The whole port range is probed 337 | pipr_entry_idx = 0; 338 | } 339 | } 340 | clock_gettime(CLOCK_REALTIME, ¤t_time); 341 | printf("Debug: Install probe ip range " 342 | "entries into t1 within %f seconds\n", 343 | ((current_time.tv_sec - start_time.tv_sec) * 1000000000.0 + \ 344 | current_time.tv_nsec - start_time.tv_nsec) / 1000000000.0); 345 | } 346 | 347 | // Configure the probe port 348 | probe_port_stride_config(iswitch, 349 | (uint16_t)ceil(PIPR_ENTRY_COUNT * 1.0 / IP_RANGE_TABLE_SIZE)); 350 | probe_port_config(iswitch, iconf->probe_port_range.start); 351 | 352 | imap_status = creat_update_notifying_channel(&update_channel); 353 | if (imap_status == 0) { 354 | printf("ichannel: The update notifying channel " 355 | "is created successfully!\n"); 356 | } 357 | else { 358 | printf("ichannel: The update notifying channel " 359 | "is not created successfully!\n"); 360 | } 361 | 362 | clock_gettime(CLOCK_REALTIME, &start_time); 363 | #if __PROBE_TYPE__ == PROBE_TYPE_SYN_PROBER 364 | imap_status = send_syn_temp_to_switch(); 365 | #elif __PROBE_TYPE__ == PROBE_TYPE_ICMP_PROBER 366 | imap_status = send_icmp_temp_to_switch(); 367 | #endif 368 | if (imap_status == 0) { 369 | printf("ichannel: The template packets are " 370 | "sent to the data plane of IMap\n"); 371 | } 372 | else { 373 | printf("ichannel: The template packets can not " 374 | "be sent to the data plane of IMap\n"); 375 | } 376 | clock_gettime(CLOCK_REALTIME, ¤t_time); 377 | printf("Send template packets into the data plane within %f seconds\n", 378 | ((current_time.tv_sec - start_time.tv_sec) * 1000000000.0 + \ 379 | current_time.tv_nsec - start_time.tv_nsec) / 1000000000.0); 380 | 381 | clock_gettime(CLOCK_REALTIME, &start_time); 382 | 383 | /* Receive packet */ 384 | while (not_completed != 0) { 385 | imap_status = recv_update_notification(&update_channel); 386 | if (imap_status == 0) { 387 | // printf("Debug: pipr idx %u\n", update_channel.pipr_idx); 388 | // clock_gettime(CLOCK_REALTIME, ¤t_time); 389 | // printf("The probe packets are all sent within %f seconds\n", 390 | // ((current_time.tv_sec - start_time.tv_sec) * 1000000000.0 + \ 391 | // current_time.tv_nsec - start_time.tv_nsec) / 1000000000.0); 392 | printf("Debug: probe table %hhu has been probed\n", 393 | update_channel.probe_table); 394 | not_completed -= 1; 395 | if (pipr_entry_idx == PIPR_ENTRY_COUNT && port_range_size == 0) { 396 | // The probe space has been depoyed into the data plane 397 | // totally, and enter the next notification receiving loop. 398 | continue; 399 | } 400 | probe_ip_range_table_reset(iswitch, update_channel.probe_table); 401 | // Employ "multiplicative group of integers modulo n" again 402 | if (PIPR_ENTRY_COUNT - pipr_entry_idx < IP_RANGE_TABLE_SIZE) { 403 | // The pipr table can not be loaded fully this time 404 | batch_size = PIPR_ENTRY_COUNT - pipr_entry_idx; 405 | // We add an extra entry in the last slot to ensure the correctness 406 | pipr_entry.start = IP_PLACEHOLDER; 407 | pipr_entry.end = pipr_entry.start + (entry_size - 1); 408 | probe_ip_range_table_install(iswitch, 409 | update_channel.probe_table, 410 | IP_RANGE_TABLE_SIZE - 1, 411 | &pipr_entry); 412 | } 413 | else { 414 | batch_size = IP_RANGE_TABLE_SIZE; 415 | } 416 | probe_ip_range_table_install_batch(iswitch, 417 | update_channel.probe_table, 0, 418 | batch_size, 419 | &PIPR_ENTRIES[pipr_entry_idx]); 420 | pipr_entry_idx += batch_size; 421 | not_completed += 1; 422 | printf("Debug: %lu probe ip range entries are left for port %hu\n", 423 | PIPR_ENTRY_COUNT - pipr_entry_idx, 424 | iconf->probe_port_range.end - port_range_size + 1); 425 | if (pipr_entry_idx == PIPR_ENTRY_COUNT) { 426 | // The pipr entries are all loaded 427 | if (port_range_size != 0) { 428 | // The current port is probed, considering the next probe 429 | // port in the range 430 | port_range_size -= 1; 431 | } 432 | if (port_range_size != 0) { 433 | // The whole port range is probed 434 | pipr_entry_idx = 0; 435 | } 436 | } 437 | } 438 | else { 439 | printf("ichannel: The update notification is not received\n"); 440 | } 441 | } 442 | 443 | clock_gettime(CLOCK_REALTIME, ¤t_time); 444 | printf("The probe packets are all sent within %f seconds\n", 445 | ((current_time.tv_sec - start_time.tv_sec) * 1000000000.0 + \ 446 | current_time.tv_nsec - start_time.tv_nsec) / 1000000000.0); 447 | 448 | printf("Waiting %u seconds for receiving " 449 | "probe responsing packets\n", iconf->waiting_time); 450 | 451 | sleep(iconf->waiting_time); 452 | 453 | imap_status = send_flush_request_to_switch(); 454 | if (imap_status == 0) { 455 | printf("ichannel: The flush request packet is " 456 | "sent to the data plane of IMap\n"); 457 | } 458 | else { 459 | printf("ichannel: The flush request packet can not " 460 | "be sent to the data plane of IMap\n"); 461 | } 462 | 463 | printf("The scan task is completed!\n"); 464 | } 465 | 466 | int main(int argc, char *argv[]) { 467 | int imap_status = 0; 468 | imap_conf_t iconf; 469 | iswitch_t iswitch; 470 | probe_entry_t *probe_space_entries; 471 | uint32_t probe_space_entries_count; 472 | // Parse cmd options 473 | parse_options(&iconf, argc, argv); 474 | 475 | config_file_parse(iconf.config_filename, 476 | &probe_space_entries, 477 | &probe_space_entries_count); 478 | 479 | // The configuration iconf.probe_period can further be configured 480 | //based on the network utilization 481 | imap_status = launch_iswitch(&iswitch, FORWARD_LIST, ARRLEN(FORWARD_LIST)); 482 | if (imap_status == 0) { 483 | printf("iswitch: The data plane of IMap is launched correctly!\n"); 484 | } 485 | else { 486 | printf("iswitch: The data plane of IMap " 487 | "is not launched correctly!\n"); 488 | } 489 | 490 | // Configure the probe period 491 | probe_period_config(&iswitch, iconf.probe_period); 492 | 493 | start_scanner(&iconf, &iswitch, probe_space_entries, 494 | probe_space_entries_count); 495 | 496 | // while (1); 497 | 498 | return 0; 499 | } 500 | -------------------------------------------------------------------------------- /src/switch/ichannel.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: ichannel.c 3 | > Author: Guanyu Li 4 | > Mail: dracula.guanyu.li@gmail.com 5 | > Created Time: Mon 14 Dec 2020 10:23:02 AM CST 6 | > Description: Program about probe modules of IMap 7 | ************************************************************************/ 8 | 9 | #include "../iconfig.h" 10 | #include "ichannel.h" 11 | 12 | /* 13 | Checksums - IP and TCP 14 | */ 15 | static unsigned short csum(unsigned short *ptr,int nbytes) { 16 | register long sum; 17 | unsigned short oddbyte; 18 | register short answer; 19 | 20 | sum = 0; 21 | while (nbytes > 1) { 22 | sum += *ptr++; 23 | nbytes -= 2; 24 | } 25 | if (nbytes == 1) { 26 | oddbyte = 0; 27 | *((u_char*)&oddbyte)= *(u_char*)ptr; 28 | sum += oddbyte; 29 | } 30 | 31 | sum = (sum >> 16) + (sum & 0xffff); 32 | sum = sum + (sum >> 16); 33 | answer = (short)~sum; 34 | 35 | return answer; 36 | } 37 | 38 | #if __IP_TYPE__ == 6 39 | int send_ipv6_syn_temp_to_switch() { 40 | int sockfd; 41 | struct ifreq cpuif_req; 42 | int tx_len = 0; 43 | char sendbuf[PKTBUF_SIZE]; 44 | struct ethhdr *eth_h = (struct ethhdr *)sendbuf; 45 | struct ipv6hdr *ipv6_h = (struct ipv6hdr *) 46 | ((char *)eth_h + sizeof(struct ethhdr)); 47 | struct tcphdr *tcp_h = (struct tcphdr *) 48 | ((char *)ipv6_h + sizeof(struct ipv6hdr)); 49 | struct psdv6hdr psd_h; 50 | struct sockaddr_ll sock_addr; 51 | char cpuif_name[IFNAMSIZ]; 52 | 53 | /* Get interface name */ 54 | strcpy(cpuif_name, CPUIF_NAME); 55 | 56 | /* Open RAW socket to send on */ 57 | if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) == -1) { 58 | perror("socket"); 59 | return -1; 60 | } 61 | 62 | /* Get the index of the interface to send on */ 63 | memset(&cpuif_req, 0, sizeof(struct ifreq)); 64 | strncpy(cpuif_req.ifr_name, cpuif_name, IFNAMSIZ - 1); 65 | if (ioctl(sockfd, SIOCGIFINDEX, &cpuif_req) < 0) { 66 | perror("SIOCGIFINDEX"); 67 | close(sockfd); 68 | return -1; 69 | } 70 | 71 | /* Construct the Ethernet header */ 72 | memset(sendbuf, 0, PKTBUF_SIZE); 73 | /* Ethernet header */ 74 | for (unsigned int idx = 0; idx < 6; idx++) { 75 | eth_h->h_source[idx] = MAC_ARRAY(PROBER_MAC, idx); 76 | } 77 | eth_h->h_proto = htons(ETH_P_IPV6); 78 | tx_len += sizeof(struct ethhdr); 79 | 80 | /* IP header */ 81 | ipv6_h->version = 6; 82 | ipv6_h->priority = 0; 83 | ipv6_h->flow_lbl[0] = 0; 84 | ipv6_h->flow_lbl[1] = 0; 85 | ipv6_h->flow_lbl[2] = 0; 86 | ipv6_h->payload_len = htons(sizeof(struct tcphdr)); 87 | ipv6_h->nexthdr = IPPROTO_TCP; 88 | ipv6_h->hop_limit = 128; 89 | for (unsigned int idx = 0; idx < 4; idx++) { 90 | ipv6_h->saddr.__in6_u.__u6_addr8[idx + 0] = \ 91 | IPV6_ARRAY(PROBER_IPV6_P1, idx); 92 | } 93 | for (unsigned int idx = 0; idx < 4; idx++) { 94 | ipv6_h->saddr.__in6_u.__u6_addr8[idx + 4] = \ 95 | IPV6_ARRAY(PROBER_IPV6_P2, idx); 96 | } 97 | for (unsigned int idx = 0; idx < 4; idx++) { 98 | ipv6_h->saddr.__in6_u.__u6_addr8[idx + 8] = \ 99 | IPV6_ARRAY(PROBER_IPV6_P3, idx); 100 | } 101 | for (unsigned int idx = 0; idx < 4; idx++) { 102 | ipv6_h->saddr.__in6_u.__u6_addr8[idx + 12] = \ 103 | IPV6_ARRAY(PROBER_IPV6_P4, idx); 104 | } 105 | 106 | tx_len += sizeof(struct ipv6hdr); 107 | 108 | /* TCP header */ 109 | tcp_h->seq = htonl(123456789); 110 | tcp_h->ack_seq = htonl(0); 111 | tcp_h->doff = sizeof(struct tcphdr) / 4; 112 | tcp_h->fin=0; 113 | tcp_h->syn=1; 114 | tcp_h->rst=0; 115 | tcp_h->psh=0; 116 | tcp_h->ack=0; 117 | tcp_h->urg=0; 118 | tcp_h->window = htons(1024); 119 | tcp_h->check = 0; 120 | tcp_h->urg_ptr = 0; 121 | tx_len += sizeof(struct tcphdr); 122 | 123 | // TCP Checksum 124 | psd_h.saddr = ipv6_h->saddr; 125 | psd_h.daddr = ipv6_h->daddr; 126 | psd_h.placeholder = 0; 127 | psd_h.protocol = ipv6_h->nexthdr; 128 | psd_h.tcp_length = 129 | htons(tx_len - sizeof(struct ethhdr) - sizeof(struct ipv6hdr)); 130 | memcpy(&psd_h.tcp , tcp_h , sizeof (struct tcphdr)); 131 | tcp_h->check = csum((uint16_t *)&psd_h, sizeof(struct psdv6hdr)); 132 | 133 | /* Packet data */ 134 | // sendbuf[tx_len++] = 0xde; 135 | // sendbuf[tx_len++] = 0xad; 136 | // sendbuf[tx_len++] = 0xbe; 137 | // sendbuf[tx_len++] = 0xef; 138 | 139 | /* Index of the network device */ 140 | sock_addr.sll_ifindex = cpuif_req.ifr_ifindex; 141 | /* Address length*/ 142 | sock_addr.sll_halen = ETH_ALEN; 143 | /* Destination MAC */ 144 | // sock_addr.sll_addr[0] = 0; 145 | // sock_addr.sll_addr[1] = 0; 146 | // sock_addr.sll_addr[2] = 0; 147 | // sock_addr.sll_addr[3] = 0; 148 | // sock_addr.sll_addr[4] = 0; 149 | // sock_addr.sll_addr[5] = 0; 150 | 151 | /* Send packet */ 152 | if (sendto(sockfd, sendbuf, tx_len, 0, 153 | (struct sockaddr *)&sock_addr, sizeof(struct sockaddr_ll)) < 0) { 154 | printf("Send failed\n"); 155 | } 156 | 157 | return 0; 158 | } 159 | 160 | int recv_ipv6_probe_report_from_switch() { 161 | int sockfd; 162 | struct ifreq cpuif_req; 163 | int rx_len = 0; 164 | char recvbuf[PKTBUF_SIZE]; 165 | struct sockaddr_ll sock_addr; 166 | int sock_addrlen = sizeof(sock_addr); 167 | char cpuif_name[IFNAMSIZ]; 168 | 169 | /* Get interface name */ 170 | strcpy(cpuif_name, CPUIF_NAME); 171 | 172 | /* Header structures */ 173 | struct ethhdr *eth_h = (struct ethhdr *)recvbuf; 174 | struct ipv6hdr *ipv6_h = (struct ipv6hdr *) 175 | ((char *)eth_h + sizeof(struct ethhdr)); 176 | struct tcphdr *tcp_h = (struct tcphdr *) 177 | ((char *)ipv6_h + sizeof(struct ipv6hdr)); 178 | 179 | /* Open RAW socket to send on */ 180 | if ((sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IPV6))) == -1) { 181 | perror("socket"); 182 | return -1; 183 | } 184 | 185 | memset(&cpuif_req, 0, sizeof(struct ifreq)); 186 | strncpy(cpuif_req.ifr_name, cpuif_name, IFNAMSIZ - 1); 187 | ioctl(sockfd, SIOCGIFFLAGS, &cpuif_req); 188 | cpuif_req.ifr_flags |= IFF_PROMISC; 189 | ioctl(sockfd, SIOCSIFFLAGS, &cpuif_req); 190 | 191 | if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, 192 | cpuif_name, IFNAMSIZ - 1) == -1) { 193 | perror("SO_BINDTODEVICE"); 194 | close(sockfd); 195 | return -1; 196 | } 197 | 198 | /* Construct the Ethernet header */ 199 | memset(recvbuf, 0, PKTBUF_SIZE); 200 | 201 | /* Receive packet */ 202 | while (1) { 203 | rx_len = recvfrom(sockfd, recvbuf, PKTBUF_SIZE, 0, NULL, NULL); 204 | if (rx_len < 0) { 205 | printf("Recv failed\n"); 206 | } 207 | else { 208 | // BUG: Here we can receive packets from other NICs! 209 | // So we need filter the packets from the switch 210 | if ((eth_h->h_dest[0] == MAC_ARRAY(PROBER_MAC, 0)) && 211 | (eth_h->h_dest[1] == MAC_ARRAY(PROBER_MAC, 1)) && 212 | (eth_h->h_dest[2] == MAC_ARRAY(PROBER_MAC, 2)) && 213 | (eth_h->h_dest[3] == MAC_ARRAY(PROBER_MAC, 3)) && 214 | (eth_h->h_dest[4] == MAC_ARRAY(PROBER_MAC, 4)) && 215 | (eth_h->h_dest[5] == MAC_ARRAY(PROBER_MAC, 5))) { 216 | 217 | char probe_ip[INET6_ADDRSTRLEN]; 218 | inet_ntop(AF_INET6, &ipv6_h->saddr, probe_ip, sizeof(probe_ip)); 219 | 220 | if (tcp_h->syn == 1) { 221 | printf("Port %u of %s is active!\n", 222 | ntohs(tcp_h->source), probe_ip); 223 | } 224 | else if (tcp_h->rst == 1) { 225 | printf("Port %u of %s is inactive!\n", 226 | ntohs(tcp_h->source), probe_ip); 227 | } 228 | } 229 | } 230 | } 231 | 232 | return 0; 233 | } 234 | #else 235 | int sendpkt_to_switch() { 236 | int sockfd; 237 | struct ifreq cpuif_req; 238 | int tx_len = 0; 239 | char sendbuf[PKTBUF_SIZE]; 240 | struct sockaddr_ll sock_addr; 241 | char cpuif_name[IFNAMSIZ]; 242 | 243 | /* Get interface name */ 244 | strcpy(cpuif_name, CPUIF_NAME); 245 | 246 | /* Open RAW socket to send on */ 247 | if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) == -1) { 248 | perror("socket"); 249 | close(sockfd); 250 | return -1; 251 | } 252 | 253 | /* Get the index of the interface to send on */ 254 | memset(&cpuif_req, 0, sizeof(struct ifreq)); 255 | strncpy(cpuif_req.ifr_name, cpuif_name, IFNAMSIZ - 1); 256 | if (ioctl(sockfd, SIOCGIFINDEX, &cpuif_req) < 0) { 257 | perror("SIOCGIFINDEX"); 258 | close(sockfd); 259 | return -1; 260 | } 261 | 262 | /* Construct the Ethernet header */ 263 | memset(sendbuf, 0, PKTBUF_SIZE); 264 | tx_len += sizeof(struct ethhdr); 265 | 266 | /* Index of the network device */ 267 | sock_addr.sll_ifindex = cpuif_req.ifr_ifindex; 268 | 269 | /* Send packet */ 270 | if (sendto(sockfd, sendbuf, tx_len, 0, 271 | (struct sockaddr *)&sock_addr, sizeof(struct sockaddr_ll)) < 0) { 272 | printf("Send failed\n"); 273 | return -1; 274 | } 275 | 276 | return 0; 277 | } 278 | 279 | int send_syn_temp_to_switch() { 280 | int sockfd; 281 | struct ifreq cpuif_req; 282 | int tx_len = 0; 283 | char sendbuf[PKTBUF_SIZE]; 284 | struct ethhdr *eth_h = (struct ethhdr *)sendbuf; 285 | struct iphdr *ip_h = (struct iphdr *) 286 | ((char *)eth_h + sizeof(struct ethhdr)); 287 | struct tcphdr *tcp_h = (struct tcphdr *) 288 | ((char *)ip_h + sizeof(struct iphdr)); 289 | struct psdhdr psd_h; 290 | struct sockaddr_ll sock_addr; 291 | char cpuif_name[IFNAMSIZ]; 292 | 293 | /* Get interface name */ 294 | strcpy(cpuif_name, CPUIF_NAME); 295 | 296 | /* Open RAW socket to send on */ 297 | if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) == -1) { 298 | perror("socket"); 299 | return -1; 300 | } 301 | 302 | /* Get the index of the interface to send on */ 303 | memset(&cpuif_req, 0, sizeof(struct ifreq)); 304 | strncpy(cpuif_req.ifr_name, cpuif_name, IFNAMSIZ - 1); 305 | if (ioctl(sockfd, SIOCGIFINDEX, &cpuif_req) < 0) { 306 | perror("SIOCGIFINDEX"); 307 | close(sockfd); 308 | return -1; 309 | } 310 | 311 | /* Construct the Ethernet header */ 312 | memset(sendbuf, 0, PKTBUF_SIZE); 313 | /* Ethernet header */ 314 | for (unsigned int idx = 0; idx < 6; idx++) { 315 | eth_h->h_source[idx] = MAC_ARRAY(PROBER_MAC, idx); 316 | } 317 | eth_h->h_proto = htons(ETHER_TYPE_ITEMPLATE); 318 | tx_len += sizeof(struct ethhdr); 319 | 320 | /* IP header */ 321 | ip_h->ihl = 5; 322 | ip_h->version = 4; 323 | ip_h->tos = 0; 324 | ip_h->tot_len = htons(sizeof(struct iphdr) + sizeof(struct tcphdr)); 325 | ip_h->id = htons(12345); 326 | ip_h->ttl = 128; 327 | ip_h->protocol = IPPROTO_TCP; 328 | ip_h->check = 0; 329 | ip_h->saddr = htonl(PROBER_IP); 330 | // ip_h->daddr = inet_addr("192.168.40.134"); 331 | // IP Checksum 332 | ip_h->check = csum ((uint16_t *)ip_h, sizeof(struct iphdr)); 333 | tx_len += sizeof(struct iphdr); 334 | 335 | /* TCP header */ 336 | tcp_h->seq = htonl(123456789); 337 | tcp_h->ack_seq = htonl(0); 338 | tcp_h->doff = sizeof(struct tcphdr) / 4; 339 | tcp_h->fin=0; 340 | tcp_h->syn=1; 341 | tcp_h->rst=0; 342 | tcp_h->psh=0; 343 | tcp_h->ack=0; 344 | tcp_h->urg=0; 345 | tcp_h->window = htons(1024); 346 | tcp_h->check = 0; 347 | tcp_h->urg_ptr = 0; 348 | tx_len += sizeof(struct tcphdr); 349 | 350 | // TCP Checksum 351 | psd_h.saddr = ip_h->saddr; 352 | psd_h.daddr = ip_h->daddr; 353 | psd_h.placeholder = 0; 354 | psd_h.protocol = ip_h->protocol; 355 | psd_h.tcp_length = 356 | htons(tx_len - sizeof(struct ethhdr) - sizeof(struct iphdr)); 357 | memcpy(&psd_h.tcp , tcp_h , sizeof (struct tcphdr)); 358 | tcp_h->check = csum((uint16_t *)&psd_h, sizeof(struct psdhdr)); 359 | 360 | /* Packet data */ 361 | // sendbuf[tx_len++] = 0xde; 362 | // sendbuf[tx_len++] = 0xad; 363 | // sendbuf[tx_len++] = 0xbe; 364 | // sendbuf[tx_len++] = 0xef; 365 | 366 | /* Index of the network device */ 367 | sock_addr.sll_ifindex = cpuif_req.ifr_ifindex; 368 | /* Address length*/ 369 | sock_addr.sll_halen = ETH_ALEN; 370 | /* Destination MAC */ 371 | // sock_addr.sll_addr[0] = 0; 372 | // sock_addr.sll_addr[1] = 0; 373 | // sock_addr.sll_addr[2] = 0; 374 | // sock_addr.sll_addr[3] = 0; 375 | // sock_addr.sll_addr[4] = 0; 376 | // sock_addr.sll_addr[5] = 0; 377 | 378 | /* Send packet */ 379 | for (uint32_t idx = 0; idx < 50000; idx++) { 380 | if (sendto(sockfd, sendbuf, tx_len, 0, 381 | (struct sockaddr *)&sock_addr, sizeof(struct sockaddr_ll)) < 0) { 382 | printf("Send failed\n"); 383 | } 384 | } 385 | 386 | return 0; 387 | } 388 | 389 | int send_icmp_temp_to_switch() { 390 | int sockfd; 391 | struct ifreq cpuif_req; 392 | int tx_len = 0; 393 | char sendbuf[PKTBUF_SIZE]; 394 | struct ethhdr *eth_h = (struct ethhdr *)sendbuf; 395 | struct iphdr *ip_h = (struct iphdr *) 396 | ((char *)eth_h + sizeof(struct ethhdr)); 397 | struct icmphdr *icmp_h = (struct icmphdr *) 398 | ((char *)ip_h + sizeof(struct iphdr)); 399 | struct sockaddr_ll sock_addr; 400 | char cpuif_name[IFNAMSIZ]; 401 | 402 | /* Get interface name */ 403 | strcpy(cpuif_name, CPUIF_NAME); 404 | 405 | /* Open RAW socket to send on */ 406 | if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) == -1) { 407 | perror("socket"); 408 | return -1; 409 | } 410 | 411 | /* Get the index of the interface to send on */ 412 | memset(&cpuif_req, 0, sizeof(struct ifreq)); 413 | strncpy(cpuif_req.ifr_name, cpuif_name, IFNAMSIZ - 1); 414 | if (ioctl(sockfd, SIOCGIFINDEX, &cpuif_req) < 0) { 415 | perror("SIOCGIFINDEX"); 416 | close(sockfd); 417 | return -1; 418 | } 419 | 420 | /* Construct the Ethernet header */ 421 | memset(sendbuf, 0, PKTBUF_SIZE); 422 | /* Ethernet header */ 423 | for (unsigned int idx = 0; idx < 6; idx++) { 424 | eth_h->h_source[idx] = MAC_ARRAY(PROBER_MAC, idx); 425 | } 426 | eth_h->h_proto = htons(ETHER_TYPE_ITEMPLATE); 427 | tx_len += sizeof(struct ethhdr); 428 | 429 | /* IP header */ 430 | ip_h->ihl = 5; 431 | ip_h->version = 4; 432 | ip_h->tos = 0; 433 | ip_h->tot_len = htons(sizeof(struct iphdr) + sizeof(struct tcphdr)); 434 | ip_h->id = htons(12345); 435 | ip_h->ttl = 128; 436 | ip_h->protocol = IPPROTO_ICMP; 437 | ip_h->check = 0; 438 | ip_h->saddr = htonl(PROBER_IP); 439 | // ip_h->daddr = inet_addr("192.168.40.134"); 440 | // IP Checksum 441 | ip_h->check = csum ((uint16_t *)ip_h, sizeof(struct iphdr)); 442 | tx_len += sizeof(struct iphdr); 443 | 444 | /* TCP header */ 445 | icmp_h->type = ICMP_ECHO; 446 | icmp_h->code = 0; 447 | icmp_h->checksum = 0; 448 | icmp_h->un.echo.id = 0; 449 | icmp_h->un.echo.sequence = 0; 450 | icmp_h->checksum = csum ((uint16_t *)icmp_h, sizeof(struct icmphdr) + 12); 451 | tx_len += sizeof(struct icmphdr); 452 | 453 | // /* ICMP data */ 454 | // for (uint8_t idx = 0; idx < 12; idx++) { 455 | // sendbuf[tx_len++] = 0; 456 | // } 457 | 458 | /* Index of the network device */ 459 | sock_addr.sll_ifindex = cpuif_req.ifr_ifindex; 460 | /* Address length*/ 461 | sock_addr.sll_halen = ETH_ALEN; 462 | /* Destination MAC */ 463 | // sock_addr.sll_addr[0] = 0; 464 | // sock_addr.sll_addr[1] = 0; 465 | // sock_addr.sll_addr[2] = 0; 466 | // sock_addr.sll_addr[3] = 0; 467 | // sock_addr.sll_addr[4] = 0; 468 | // sock_addr.sll_addr[5] = 0; 469 | 470 | /* Send packet */ 471 | for (uint32_t idx = 0; idx < 50000; idx++) { 472 | if (sendto(sockfd, sendbuf, tx_len, 0, 473 | (struct sockaddr *)&sock_addr, sizeof(struct sockaddr_ll)) < 0) { 474 | printf("Send failed\n"); 475 | } 476 | } 477 | 478 | return 0; 479 | } 480 | 481 | // abandon now 482 | int recv_probe_report_from_switch() { 483 | int sockfd; 484 | struct ifreq cpuif_req; 485 | int rx_len = 0; 486 | char recvbuf[PKTBUF_SIZE]; 487 | struct sockaddr_ll sock_addr; 488 | int sock_addrlen = sizeof(sock_addr); 489 | char cpuif_name[IFNAMSIZ]; 490 | 491 | /* Get interface name */ 492 | strcpy(cpuif_name, CPUIF_NAME); 493 | 494 | /* Header structures */ 495 | struct ethhdr *eth_h = (struct ethhdr *)recvbuf; 496 | struct iphdr *ip_h = (struct iphdr *) 497 | ((char *)eth_h + sizeof(struct ethhdr)); 498 | struct tcphdr *tcp_h = (struct tcphdr *) 499 | ((char *)ip_h + sizeof(struct iphdr)); 500 | 501 | /* Open RAW socket to send on */ 502 | if ((sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))) == -1) { 503 | perror("socket"); 504 | return -1; 505 | } 506 | 507 | memset(&cpuif_req, 0, sizeof(struct ifreq)); 508 | strncpy(cpuif_req.ifr_name, cpuif_name, IFNAMSIZ - 1); 509 | ioctl(sockfd, SIOCGIFFLAGS, &cpuif_req); 510 | cpuif_req.ifr_flags |= IFF_PROMISC; 511 | ioctl(sockfd, SIOCSIFFLAGS, &cpuif_req); 512 | 513 | if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, 514 | cpuif_name, IFNAMSIZ - 1) == -1) { 515 | perror("SO_BINDTODEVICE"); 516 | close(sockfd); 517 | return -1; 518 | } 519 | 520 | /* Construct the Ethernet header */ 521 | memset(recvbuf, 0, PKTBUF_SIZE); 522 | 523 | /* Receive packet */ 524 | while (1) { 525 | rx_len = recvfrom(sockfd, recvbuf, PKTBUF_SIZE, 0, NULL, NULL); 526 | if (rx_len < 0) { 527 | printf("Recv failed\n"); 528 | } 529 | else { 530 | // printf("ethertype: %x\n",ntohs(eth_h->h_proto)); 531 | // BUG: Here we can receive packets from other NICs! 532 | // So we need filter the packets from the switch 533 | if ((eth_h->h_dest[0] == MAC_ARRAY(PROBER_MAC, 0)) && 534 | (eth_h->h_dest[1] == MAC_ARRAY(PROBER_MAC, 1)) && 535 | (eth_h->h_dest[2] == MAC_ARRAY(PROBER_MAC, 2)) && 536 | (eth_h->h_dest[3] == MAC_ARRAY(PROBER_MAC, 3)) && 537 | (eth_h->h_dest[4] == MAC_ARRAY(PROBER_MAC, 4)) && 538 | (eth_h->h_dest[5] == MAC_ARRAY(PROBER_MAC, 5))) { 539 | 540 | char probe_ip[INET6_ADDRSTRLEN]; 541 | inet_ntop(AF_INET, &ip_h->saddr, probe_ip, sizeof(probe_ip)); 542 | 543 | if (tcp_h->syn == 1) { 544 | printf("Port %u of %s is active!\n", 545 | ntohs(tcp_h->source), probe_ip); 546 | } 547 | else if (tcp_h->rst == 1) { 548 | printf("Port %u of %s is inactive!\n", 549 | ntohs(tcp_h->source), probe_ip); 550 | } 551 | } 552 | } 553 | } 554 | 555 | return 0; 556 | } 557 | #endif 558 | 559 | int creat_update_notifying_channel(update_notifying_channel_t *channel) { 560 | struct ifreq cpuif_req; 561 | struct sockaddr_ll sock_addr; 562 | int sock_addrlen = sizeof(sock_addr); 563 | char cpuif_name[IFNAMSIZ]; 564 | 565 | /* Get interface name */ 566 | strcpy(cpuif_name, CPUIF_NAME); 567 | 568 | channel->sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETHER_TYPE_IREPORT)); 569 | /* Open RAW socket to send on */ 570 | if (channel->sockfd == -1) { 571 | perror("socket"); 572 | return -1; 573 | } 574 | 575 | memset(&cpuif_req, 0, sizeof(struct ifreq)); 576 | strncpy(cpuif_req.ifr_name, cpuif_name, IFNAMSIZ - 1); 577 | ioctl(channel->sockfd, SIOCGIFFLAGS, &cpuif_req); 578 | cpuif_req.ifr_flags |= IFF_PROMISC; 579 | ioctl(channel->sockfd, SIOCSIFFLAGS, &cpuif_req); 580 | 581 | if (setsockopt(channel->sockfd, SOL_SOCKET, SO_BINDTODEVICE, 582 | cpuif_name, IFNAMSIZ - 1) == -1) { 583 | perror("SO_BINDTODEVICE"); 584 | close(channel->sockfd); 585 | return -1; 586 | } 587 | 588 | /* Construct the Ethernet header */ 589 | memset(channel->recvbuf, 0, PKTBUF_SIZE); 590 | 591 | return 0; 592 | } 593 | 594 | int recv_update_notification(update_notifying_channel_t *channel) { 595 | int rx_len = 0; 596 | 597 | /* Header structures */ 598 | struct ethhdr *eth_h = (struct ethhdr *)channel->recvbuf; 599 | uint8_t *probe_table = (uint8_t *)((char *)eth_h + sizeof(struct ethhdr)); 600 | uint16_t *pipr_idx = (uint16_t *)((char *)probe_table + sizeof(uint8_t)); 601 | uint16_t *egress_port = (uint16_t *)((char *)pipr_idx + sizeof(uint16_t)); 602 | 603 | rx_len = recvfrom(channel->sockfd, channel->recvbuf, 604 | PKTBUF_SIZE, 0, NULL, NULL); 605 | if (rx_len < 0) { 606 | printf("Recv failed\n"); 607 | return -1; 608 | } 609 | else { 610 | channel->probe_table = *probe_table; 611 | channel->pipr_idx = htons(*pipr_idx); 612 | channel->egress_port = htons(*egress_port); 613 | return 0; 614 | } 615 | } 616 | 617 | //abandon now 618 | int recv_update_notification_from_switch(uint32_t timer, uint8_t *pipr_filter) { 619 | int sockfd; 620 | struct ifreq cpuif_req; 621 | int rx_len = 0; 622 | char recvbuf[PKTBUF_SIZE]; 623 | struct sockaddr_ll sock_addr; 624 | int sock_addrlen = sizeof(sock_addr); 625 | char cpuif_name[IFNAMSIZ]; 626 | time_t start_time, current_time; 627 | uint32_t not_completed = 0; 628 | 629 | /* Header structures */ 630 | struct ethhdr *eth_h = (struct ethhdr *)recvbuf; 631 | uint16_t *pipr_idx = (uint16_t *)((char *)eth_h + sizeof(struct ethhdr)); 632 | uint16_t *egress_port = (uint16_t *)((char *)pipr_idx + sizeof(uint16_t)); 633 | 634 | /* Get interface name */ 635 | strcpy(cpuif_name, CPUIF_NAME); 636 | 637 | sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETHER_TYPE_IREPORT)); 638 | /* Open RAW socket to send on */ 639 | if (sockfd == -1) { 640 | perror("socket"); 641 | return -1; 642 | } 643 | 644 | memset(&cpuif_req, 0, sizeof(struct ifreq)); 645 | strncpy(cpuif_req.ifr_name, cpuif_name, IFNAMSIZ - 1); 646 | ioctl(sockfd, SIOCGIFFLAGS, &cpuif_req); 647 | cpuif_req.ifr_flags |= IFF_PROMISC; 648 | ioctl(sockfd, SIOCSIFFLAGS, &cpuif_req); 649 | 650 | if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, 651 | cpuif_name, IFNAMSIZ - 1) == -1) { 652 | perror("SO_BINDTODEVICE"); 653 | close(sockfd); 654 | return -1; 655 | } 656 | 657 | /* Construct the Ethernet header */ 658 | memset(recvbuf, 0, PKTBUF_SIZE); 659 | 660 | start_time = time(NULL); 661 | 662 | /* Receive packet */ 663 | while (1) { 664 | current_time = time(NULL); 665 | if (difftime(current_time, start_time) > timer) { 666 | break; 667 | } 668 | rx_len = recvfrom(sockfd, recvbuf, PKTBUF_SIZE, 0, NULL, NULL); 669 | if (rx_len < 0) { 670 | printf("Recv failed\n"); 671 | } 672 | else { 673 | // // BUG: Here we can receive packets from other NICs! 674 | // // So we need filter the packets from the switch 675 | // if ((eth_h->h_source[0] == MAC_ARRAY(PROBER_MAC, 0)) && 676 | // (eth_h->h_source[1] == MAC_ARRAY(PROBER_MAC, 1)) && 677 | // (eth_h->h_source[2] == MAC_ARRAY(PROBER_MAC, 2)) && 678 | // (eth_h->h_source[3] == MAC_ARRAY(PROBER_MAC, 3)) && 679 | // (eth_h->h_source[4] == MAC_ARRAY(PROBER_MAC, 4)) && 680 | // (eth_h->h_source[5] == MAC_ARRAY(PROBER_MAC, 5))) { 681 | 682 | // printf("The probe ip range (idx: %u, port: %u) is probed " 683 | // "completely\n", htons(*pipr_idx), htons(*egress_port)); 684 | // } 685 | if (pipr_filter[htons(*pipr_idx)] == 1) { 686 | pipr_filter[htons(*pipr_idx)] = 2; 687 | } 688 | } 689 | } 690 | 691 | for (uint32_t idx = 0; idx < IP_RANGE_TABLE_SIZE; idx++) { 692 | if (pipr_filter[idx] == 1) { 693 | printf("The probe ip range (%u) is not probed completely\n", idx); 694 | not_completed += 1; 695 | } 696 | } 697 | 698 | printf("The probe task is completed with %u probe ip " 699 | "range not probed completely\n", not_completed); 700 | 701 | return 0; 702 | } 703 | 704 | int send_flush_request_to_switch() { 705 | int sockfd; 706 | struct ifreq cpuif_req; 707 | int tx_len = 0; 708 | char sendbuf[PKTBUF_SIZE]; 709 | struct ethhdr *eth_h = (struct ethhdr *)sendbuf; 710 | struct psdhdr psd_h; 711 | struct sockaddr_ll sock_addr; 712 | char cpuif_name[IFNAMSIZ]; 713 | 714 | /* Get interface name */ 715 | strcpy(cpuif_name, CPUIF_NAME); 716 | 717 | /* Open RAW socket to send on */ 718 | if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) == -1) { 719 | perror("socket"); 720 | return -1; 721 | } 722 | 723 | /* Get the index of the interface to send on */ 724 | memset(&cpuif_req, 0, sizeof(struct ifreq)); 725 | strncpy(cpuif_req.ifr_name, cpuif_name, IFNAMSIZ - 1); 726 | if (ioctl(sockfd, SIOCGIFINDEX, &cpuif_req) < 0) { 727 | perror("SIOCGIFINDEX"); 728 | close(sockfd); 729 | return -1; 730 | } 731 | 732 | /* Construct the Ethernet header */ 733 | memset(sendbuf, 0, PKTBUF_SIZE); 734 | /* Ethernet header */ 735 | for (unsigned int idx = 0; idx < 6; idx++) { 736 | eth_h->h_source[idx] = MAC_ARRAY(PROBER_MAC, idx); 737 | } 738 | eth_h->h_proto = htons(ETHER_TYPE_IFLUSH); 739 | tx_len += sizeof(struct ethhdr); 740 | 741 | /* Packet data */ 742 | // sendbuf[tx_len++] = 0xde; 743 | // sendbuf[tx_len++] = 0xad; 744 | // sendbuf[tx_len++] = 0xbe; 745 | // sendbuf[tx_len++] = 0xef; 746 | 747 | /* Index of the network device */ 748 | sock_addr.sll_ifindex = cpuif_req.ifr_ifindex; 749 | /* Address length*/ 750 | sock_addr.sll_halen = ETH_ALEN; 751 | /* Destination MAC */ 752 | // sock_addr.sll_addr[0] = 0; 753 | // sock_addr.sll_addr[1] = 0; 754 | // sock_addr.sll_addr[2] = 0; 755 | // sock_addr.sll_addr[3] = 0; 756 | // sock_addr.sll_addr[4] = 0; 757 | // sock_addr.sll_addr[5] = 0; 758 | 759 | /* Send packet */ 760 | if (sendto(sockfd, sendbuf, tx_len, 0, 761 | (struct sockaddr *)&sock_addr, sizeof(struct sockaddr_ll)) < 0) { 762 | printf("Send failed\n"); 763 | } 764 | 765 | return 0; 766 | } 767 | -------------------------------------------------------------------------------- /src/switch/iswitch.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: iswitch.c 3 | > Author: Guanyu Li 4 | > Mail: dracula.guanyu.li@gmail.com 5 | > Created Time: Mon 14 Dec 2020 10:23:02 AM CST 6 | > Description: Data plane (Tofino) control interfaces for IMap 7 | ************************************************************************/ 8 | 9 | #include "../iconfig.h" 10 | #include "iswitch.h" 11 | #include 12 | 13 | static void switchd_setup(bf_switchd_context_t *switchd_ctx) { 14 | char conf_file[256]; 15 | char bf_sysfs_fname[128] = "/sys/class/bf/bf0/device"; 16 | FILE *fd; 17 | 18 | switchd_ctx->install_dir = getenv("SDE_INSTALL"); 19 | sprintf(conf_file, "%s%s", 20 | getenv("SDE_INSTALL"), "/share/p4/targets/tofino/imap.conf"); 21 | switchd_ctx->conf_file = conf_file; 22 | switchd_ctx->running_in_background = true; 23 | switchd_ctx->dev_sts_thread = true; 24 | switchd_ctx->dev_sts_port = 7777; 25 | 26 | /* Determine if kernel mode packet driver is loaded */ 27 | strncat(bf_sysfs_fname, "/dev_add", 28 | sizeof(bf_sysfs_fname) - 1 - strlen(bf_sysfs_fname)); 29 | printf("bf_sysfs_fname %s\n", bf_sysfs_fname); 30 | fd = fopen(bf_sysfs_fname, "r"); 31 | if (fd != NULL) { 32 | /* override previous parsing if bf_kpkt KLM was loaded */ 33 | printf("kernel mode packet driver present, forcing kpkt option!\n"); 34 | switchd_ctx->kernel_pkt = true; 35 | fclose(fd); 36 | } 37 | 38 | assert(bf_switchd_lib_init(switchd_ctx) == BF_SUCCESS); 39 | printf("\nbf_switchd is initialized correctly!\n"); 40 | } 41 | 42 | static void bfrt_setup(const bf_rt_target_t *dev_tgt, 43 | const bf_rt_info_hdl **bfrt_info, 44 | bf_rt_session_hdl **session) { 45 | bf_status_t bf_status; 46 | 47 | // Get bfrtInfo object from dev_id and p4 program name 48 | bf_status = bf_rt_info_get(dev_tgt->dev_id, "imap", bfrt_info); 49 | assert(bf_status == BF_SUCCESS); 50 | // Create a session object 51 | bf_status = bf_rt_session_create(session); 52 | assert(bf_status == BF_SUCCESS); 53 | printf("bfrt_info is got and session is created correctly!\n"); 54 | } 55 | 56 | static void port_setup(const bf_rt_target_t *dev_tgt, 57 | const switch_port_t *port_list, 58 | const uint8_t port_count) { 59 | bf_status_t bf_status; 60 | 61 | // Add and enable ports 62 | for (unsigned int idx = 0; idx < port_count; idx++) { 63 | bf_pal_front_port_handle_t port_hdl; 64 | bf_status = bf_pm_port_str_to_hdl_get(dev_tgt->dev_id, 65 | port_list[idx].fp_port, 66 | &port_hdl); 67 | assert(bf_status == BF_SUCCESS); 68 | bf_status = bf_pm_port_add(dev_tgt->dev_id, &port_hdl, 69 | BF_SPEED_40G, BF_FEC_TYP_NONE); 70 | assert(bf_status == BF_SUCCESS); 71 | bf_status = bf_pm_port_enable(dev_tgt->dev_id, &port_hdl); 72 | assert(bf_status == BF_SUCCESS); 73 | printf("Port %s is enabled successfully!\n", port_list[idx].fp_port); 74 | } 75 | } 76 | 77 | static void result_server_port_setup(const bf_rt_target_t *dev_tgt, 78 | const bf_dev_port_t result_server_port) { 79 | bf_status_t bf_status; 80 | 81 | // Add and enable ports 82 | bf_pal_front_port_handle_t port_hdl; 83 | bf_status = bf_pm_port_dev_port_to_front_panel_port_get(dev_tgt->dev_id, 84 | result_server_port, 85 | &port_hdl); 86 | assert(bf_status == BF_SUCCESS); 87 | bf_status = bf_pm_port_add(dev_tgt->dev_id, &port_hdl, 88 | BF_SPEED_40G, BF_FEC_TYP_NONE); 89 | assert(bf_status == BF_SUCCESS); 90 | bf_status = bf_pm_port_enable(dev_tgt->dev_id, &port_hdl); 91 | assert(bf_status == BF_SUCCESS); 92 | printf("Result server port (%u) is enabled " 93 | "successfully!\n", result_server_port); 94 | } 95 | 96 | static void result_server_multicast_setup(const bf_rt_target_t *dev_tgt, 97 | const bf_rt_info_hdl *bfrt_info) { 98 | bf_status_t bf_status; 99 | bf_mc_session_hdl_t mc_session; 100 | bf_mc_mgrp_hdl_t mc_mgrp; 101 | bf_mc_node_hdl_t mc_node; 102 | bf_mc_port_map_t mc_port_map; 103 | bf_mc_lag_map_t mc_lag_map; 104 | 105 | bf_status = bf_mc_create_session(&mc_session); 106 | assert(bf_status == BF_SUCCESS); 107 | 108 | bf_status = bf_mc_mgrp_create(mc_session, dev_tgt->dev_id, 109 | RESULT_SERVER_MC_GID, &mc_mgrp); 110 | assert(bf_status == BF_SUCCESS); 111 | 112 | BF_MC_PORT_MAP_INIT(mc_port_map); 113 | BF_MC_LAG_MAP_INIT(mc_lag_map); 114 | 115 | BF_MC_PORT_MAP_SET(mc_port_map, RESULT_SERVER_PORT); 116 | 117 | // Rid set to 0 118 | bf_status = bf_mc_node_create(mc_session, dev_tgt->dev_id, 0, 119 | mc_port_map, mc_lag_map, &mc_node); 120 | assert(bf_status == BF_SUCCESS); 121 | 122 | bf_status = bf_mc_associate_node(mc_session, dev_tgt->dev_id, 123 | mc_mgrp, mc_node, false, 0); 124 | assert(bf_status == BF_SUCCESS); 125 | 126 | bf_status = bf_mc_complete_operations(mc_session); 127 | assert(bf_status == BF_SUCCESS); 128 | 129 | bf_status = bf_mc_destroy_session(mc_session); 130 | assert(bf_status == BF_SUCCESS); 131 | printf("Muticast for cloning to CPU is set up correctly!\n"); 132 | } 133 | 134 | static void update_notifying_mirror_setup(const bf_rt_target_t *dev_tgt) { 135 | p4_pd_status_t pd_status; 136 | p4_pd_sess_hdl_t mirror_session; 137 | p4_pd_dev_target_t pd_dev_tgt = { dev_tgt->dev_id, dev_tgt->pipe_id }; 138 | p4_pd_mirror_session_info_t mirror_session_info = { 139 | .type = PD_MIRROR_TYPE_NORM, // Not sure 140 | .dir = PD_DIR_EGRESS, 141 | .id = UPDATE_NOTIFY_MIRROR_SID, 142 | .egr_port = CPU_PORT, 143 | .egr_port_v = true, 144 | .max_pkt_len = 16384 // Refer to example in Barefoot Academy 145 | }; 146 | 147 | pd_status = p4_pd_client_init(&mirror_session); 148 | assert(pd_status == BF_SUCCESS); 149 | 150 | // p4_pd_mirror_session_create() will enable the session by default 151 | pd_status = p4_pd_mirror_session_create(mirror_session, pd_dev_tgt, 152 | &mirror_session_info); 153 | assert(pd_status == BF_SUCCESS); 154 | } 155 | 156 | static void forward_table_setup(const bf_rt_target_t *dev_tgt, 157 | const bf_rt_info_hdl *bfrt_info, 158 | const bf_rt_table_hdl **forward_table, 159 | forward_table_info_t *forward_table_info, 160 | const switch_port_t *forward_list, 161 | const uint8_t forward_count) { 162 | bf_status_t bf_status; 163 | 164 | // Get table object from name 165 | bf_status = bf_rt_table_from_name_get(bfrt_info, 166 | "SwitchIngress.ti_forward", 167 | forward_table); 168 | assert(bf_status == BF_SUCCESS); 169 | 170 | // Allocate key and data once, and use reset across different uses 171 | bf_status = bf_rt_table_key_allocate(*forward_table, 172 | &forward_table_info->key); 173 | assert(bf_status == BF_SUCCESS); 174 | bf_status = bf_rt_table_data_allocate(*forward_table, 175 | &forward_table_info->data); 176 | assert(bf_status == BF_SUCCESS); 177 | 178 | // Get field-ids for key field 179 | bf_status = bf_rt_key_field_id_get(*forward_table, "hdr.ethernet.dst_mac", 180 | &forward_table_info->kid_dst_mac); 181 | assert(bf_status == BF_SUCCESS); 182 | 183 | // Get action Ids for action a_unicast 184 | bf_status = bf_rt_action_name_to_id(*forward_table, 185 | "SwitchIngress.ai_unicast", 186 | &forward_table_info->aid_unicast); 187 | assert(bf_status == BF_SUCCESS); 188 | bf_status = bf_rt_action_name_to_id(*forward_table, 189 | "SwitchIngress.ai_broadcast", 190 | &forward_table_info->aid_broadcast); 191 | assert(bf_status == BF_SUCCESS); 192 | bf_status = bf_rt_action_name_to_id(*forward_table, 193 | "SwitchIngress.ai_drop", 194 | &forward_table_info->aid_drop); 195 | assert(bf_status == BF_SUCCESS); 196 | 197 | // Get field-ids for data field 198 | bf_status = bf_rt_data_field_id_with_action_get( 199 | *forward_table, "port", 200 | forward_table_info->aid_unicast, &forward_table_info->did_port 201 | ); 202 | assert(bf_status == BF_SUCCESS); 203 | 204 | // // 205 | // Set up the multicast for ai_broadcast // 206 | // // 207 | 208 | bf_status = bf_mc_create_session(&forward_table_info->mc_session); 209 | assert(bf_status == BF_SUCCESS); 210 | 211 | bf_status = bf_mc_mgrp_create(forward_table_info->mc_session, 212 | dev_tgt->dev_id, 213 | BROADCAST_MC_GID, 214 | &forward_table_info->mc_mgrp); 215 | assert(bf_status == BF_SUCCESS); 216 | 217 | BF_MC_PORT_MAP_INIT(forward_table_info->mc_port_map); 218 | BF_MC_LAG_MAP_INIT(forward_table_info->mc_lag_map); 219 | 220 | for (unsigned idx = 0; idx < forward_count; idx++) { 221 | bf_dev_port_t dev_port; 222 | bf_status = bf_pm_port_str_to_dev_port_get( 223 | dev_tgt->dev_id, (char *)forward_list[idx].fp_port, &dev_port 224 | ); 225 | assert(bf_status == BF_SUCCESS); 226 | BF_MC_PORT_MAP_SET(forward_table_info->mc_port_map, dev_port); 227 | } 228 | 229 | // Rid set to 0 230 | bf_status = bf_mc_node_create(forward_table_info->mc_session, 231 | dev_tgt->dev_id, 0, 232 | forward_table_info->mc_port_map, 233 | forward_table_info->mc_lag_map, 234 | &forward_table_info->mc_node); 235 | assert(bf_status == BF_SUCCESS); 236 | 237 | bf_status = bf_mc_associate_node(forward_table_info->mc_session, 238 | dev_tgt->dev_id, 239 | forward_table_info->mc_mgrp, 240 | forward_table_info->mc_node, 241 | false, 0); 242 | assert(bf_status == BF_SUCCESS); 243 | 244 | bf_status = bf_mc_complete_operations(forward_table_info->mc_session); 245 | assert(bf_status == BF_SUCCESS); 246 | 247 | bf_status = bf_mc_destroy_session(forward_table_info->mc_session); 248 | assert(bf_status == BF_SUCCESS); 249 | } 250 | 251 | static void forward_table_entry_add(const bf_rt_target_t *dev_tgt, 252 | const bf_rt_session_hdl *session, 253 | const bf_rt_table_hdl *forward_table, 254 | forward_table_info_t *forward_table_info, 255 | forward_table_entry_t *forward_entry) { 256 | bf_status_t bf_status; 257 | 258 | // Reset key before use 259 | bf_rt_table_key_reset(forward_table, &forward_table_info->key); 260 | 261 | // Fill in the Key object 262 | bf_status = bf_rt_key_field_set_value_lpm(forward_table_info->key, 263 | forward_table_info->kid_dst_mac, 264 | forward_entry->dst_mac, 265 | forward_entry->match_length); 266 | assert(bf_status == BF_SUCCESS); 267 | 268 | if (strcmp(forward_entry->action, "ai_unicast") == 0) { 269 | // Reset data before use 270 | bf_rt_table_action_data_reset(forward_table, 271 | forward_table_info->aid_unicast, 272 | &forward_table_info->data); 273 | // Fill in the Data object 274 | bf_status = bf_rt_data_field_set_value(forward_table_info->data, 275 | forward_table_info->did_port, 276 | forward_entry->egress_port); 277 | assert(bf_status == BF_SUCCESS); 278 | } 279 | else if (strcmp(forward_entry->action, "ai_broadcast") == 0) { 280 | bf_rt_table_action_data_reset(forward_table, 281 | forward_table_info->aid_broadcast, 282 | &forward_table_info->data); 283 | } 284 | 285 | // Call table entry add API 286 | bf_status = bf_rt_table_entry_add(forward_table, session, dev_tgt, 287 | forward_table_info->key, 288 | forward_table_info->data); 289 | assert(bf_status == BF_SUCCESS); 290 | bf_status = bf_rt_session_complete_operations(session); 291 | assert(bf_status == BF_SUCCESS); 292 | } 293 | 294 | static void forward_table_deploy(const bf_rt_target_t *dev_tgt, 295 | const bf_rt_info_hdl *bfrt_info, 296 | const bf_rt_session_hdl *session, 297 | const switch_port_t *forward_list, 298 | const uint8_t forward_count) { 299 | bf_status_t bf_status; 300 | const bf_rt_table_hdl *forward_table = NULL; 301 | forward_table_info_t forward_table_info; 302 | 303 | // Set up the forward table 304 | forward_table_setup(dev_tgt, bfrt_info, &forward_table, 305 | &forward_table_info, forward_list, forward_count); 306 | printf("Table forward is set up correctly!\n"); 307 | 308 | // Add forward entries 309 | for (unsigned int idx = 0; idx < forward_count; idx++) { 310 | forward_table_entry_t forward_entry = { 311 | .match_length = 48, .action = "ai_unicast" 312 | }; 313 | forward_entry.dst_mac = forward_list[idx].dst_mac; 314 | bf_status = bf_pm_port_str_to_dev_port_get( 315 | dev_tgt->dev_id, 316 | (char *)forward_list[idx].fp_port, &forward_entry.egress_port 317 | ); 318 | assert(bf_status == BF_SUCCESS); 319 | forward_table_entry_add(dev_tgt, session, forward_table, 320 | &forward_table_info, &forward_entry); 321 | printf("Add entry to forward packets with dmac "MAC_FMT" to port %s\n", 322 | MAC_DATA(forward_list[idx].dst_mac), forward_list[idx].fp_port); 323 | } 324 | 325 | forward_table_entry_t forward_entry = { 326 | .dst_mac = 0xffffffffffff, .match_length = 48, 327 | .action = "ai_broadcast", .egress_port = 0 328 | }; 329 | forward_table_entry_add(dev_tgt, session, forward_table, 330 | &forward_table_info, &forward_entry); 331 | printf("Add entry for broadcast packets\n"); 332 | 333 | forward_entry.dst_mac = 0x333300000000; 334 | forward_entry.match_length = 16; 335 | forward_table_entry_add(dev_tgt, session, forward_table, 336 | &forward_table_info, &forward_entry); 337 | printf("Add entry for IPv6 broadcast packets\n"); 338 | } 339 | 340 | static void probe_resp_inactive_handler_table_setup( 341 | const bf_rt_info_hdl *bfrt_info, 342 | const bf_rt_table_hdl **handler_table, 343 | probe_resp_handler_table_info_t *handler_table_info) { 344 | bf_status_t bf_status; 345 | 346 | // Get table object from name 347 | bf_status = bf_rt_table_from_name_get( 348 | bfrt_info, "SwitchIngress.ti_probe_resp_inactive_handler", handler_table 349 | ); 350 | assert(bf_status == BF_SUCCESS); 351 | 352 | // Allocate key and data once, and use reset across different uses 353 | bf_status = bf_rt_table_key_allocate(*handler_table, 354 | &handler_table_info->key); 355 | assert(bf_status == BF_SUCCESS); 356 | bf_status = bf_rt_table_data_allocate(*handler_table, 357 | &handler_table_info->data); 358 | assert(bf_status == BF_SUCCESS); 359 | 360 | // Get field-ids for key field 361 | bf_status = bf_rt_key_field_id_get(*handler_table, 362 | "ig_md.bridged.resp_pkt_count", 363 | &handler_table_info->kid_resp_pkt_count); 364 | assert(bf_status == BF_SUCCESS); 365 | 366 | // Get action Ids 367 | bf_status = bf_rt_action_name_to_id( 368 | *handler_table, "SwitchIngress.ai_report_to_result_server", 369 | &handler_table_info->aid_report_to_result_server 370 | ); 371 | assert(bf_status == BF_SUCCESS); 372 | } 373 | 374 | static void probe_resp_active_handler_table_setup( 375 | const bf_rt_info_hdl *bfrt_info, 376 | const bf_rt_table_hdl **handler_table, 377 | probe_resp_handler_table_info_t *handler_table_info) { 378 | bf_status_t bf_status; 379 | 380 | // Get table object from name 381 | bf_status = bf_rt_table_from_name_get( 382 | bfrt_info, "SwitchIngress.ti_probe_resp_active_handler", handler_table 383 | ); 384 | assert(bf_status == BF_SUCCESS); 385 | 386 | // Allocate key and data once, and use reset across different uses 387 | bf_status = bf_rt_table_key_allocate(*handler_table, 388 | &handler_table_info->key); 389 | assert(bf_status == BF_SUCCESS); 390 | bf_status = bf_rt_table_data_allocate(*handler_table, 391 | &handler_table_info->data); 392 | assert(bf_status == BF_SUCCESS); 393 | 394 | // Get field-ids for key field 395 | bf_status = bf_rt_key_field_id_get(*handler_table, 396 | "ig_md.bridged.resp_pkt_count", 397 | &handler_table_info->kid_resp_pkt_count); 398 | assert(bf_status == BF_SUCCESS); 399 | 400 | // Get action Ids 401 | bf_status = bf_rt_action_name_to_id( 402 | *handler_table, 403 | "SwitchIngress.ai_report_to_result_server_with_multicast", 404 | &handler_table_info->aid_report_to_result_server 405 | ); 406 | assert(bf_status == BF_SUCCESS); 407 | } 408 | 409 | static void probe_resp_handler_table_entry_add( 410 | const bf_rt_target_t *dev_tgt, 411 | const bf_rt_session_hdl *session, 412 | const bf_rt_table_hdl *handler_table, 413 | probe_resp_handler_table_info_t *handler_table_info, 414 | probe_resp_handler_table_entry_t *handler_entry) { 415 | bf_status_t bf_status; 416 | 417 | // Reset key before use 418 | bf_rt_table_key_reset(handler_table, &handler_table_info->key); 419 | 420 | // Fill in the Key object 421 | bf_status = bf_rt_key_field_set_value( 422 | handler_table_info->key, 423 | handler_table_info->kid_resp_pkt_count, handler_entry->resp_pkt_count 424 | ); 425 | assert(bf_status == BF_SUCCESS); 426 | 427 | // Reset data before use 428 | bf_rt_table_action_data_reset( 429 | handler_table, 430 | handler_table_info->aid_report_to_result_server, 431 | &handler_table_info->data 432 | ); 433 | 434 | // Call table entry add API 435 | bf_status = bf_rt_table_entry_add(handler_table, session, dev_tgt, 436 | handler_table_info->key, 437 | handler_table_info->data); 438 | assert(bf_status == BF_SUCCESS); 439 | bf_status = bf_rt_session_complete_operations(session); 440 | assert(bf_status == BF_SUCCESS); 441 | } 442 | 443 | static void probe_resp_handler_table_deploy(const bf_rt_target_t *dev_tgt, 444 | const bf_rt_info_hdl *bfrt_info, 445 | const bf_rt_session_hdl *session) { 446 | bf_status_t bf_status; 447 | const bf_rt_table_hdl *active_handler_table = NULL; 448 | const bf_rt_table_hdl *inactive_handler_table = NULL; 449 | probe_resp_handler_table_info_t active_handler_table_info; 450 | probe_resp_handler_table_info_t inactive_handler_table_info; 451 | 452 | // Set up the probe response active/inactive handler table 453 | probe_resp_inactive_handler_table_setup(bfrt_info, &inactive_handler_table, 454 | &inactive_handler_table_info); 455 | probe_resp_active_handler_table_setup(bfrt_info, &active_handler_table, 456 | &active_handler_table_info); 457 | printf("Table of probe response active/" 458 | "inactive handler is set up correctly!\n"); 459 | 460 | // Add entries for reporting to result server (with multicast) 461 | probe_resp_handler_table_entry_t report_entry = { 462 | .resp_pkt_count = RESULT_DATABASE_SIZE_M1 463 | }; 464 | probe_resp_handler_table_entry_add(dev_tgt, session, 465 | active_handler_table, 466 | &active_handler_table_info, 467 | &report_entry); 468 | probe_resp_handler_table_entry_add(dev_tgt, session, 469 | inactive_handler_table, 470 | &inactive_handler_table_info, 471 | &report_entry); 472 | printf("Add entry for reporting to result server (with multicast)\n"); 473 | } 474 | 475 | static void editor_table_setup(const bf_rt_info_hdl *bfrt_info, 476 | const bf_rt_table_hdl **editor_table, 477 | editor_table_info_t *editor_table_info) { 478 | bf_status_t bf_status; 479 | 480 | // Get table object from name 481 | bf_status = bf_rt_table_from_name_get(bfrt_info, 482 | "SwitchEgress.te_editor_p1", 483 | editor_table); 484 | assert(bf_status == BF_SUCCESS); 485 | 486 | // Allocate key and data once, and use reset across different uses 487 | bf_status = bf_rt_table_key_allocate(*editor_table, 488 | &editor_table_info->key); 489 | assert(bf_status == BF_SUCCESS); 490 | bf_status = bf_rt_table_data_allocate(*editor_table, 491 | &editor_table_info->data); 492 | assert(bf_status == BF_SUCCESS); 493 | 494 | // Get field-ids for key field 495 | bf_status = bf_rt_key_field_id_get(*editor_table, "eg_intr_md.egress_port", 496 | &editor_table_info->kid_egress_port); 497 | assert(bf_status == BF_SUCCESS); 498 | 499 | // Get action Ids for action a_unicast 500 | bf_status = bf_rt_action_name_to_id(*editor_table, 501 | "SwitchEgress.ae_editor_p1", 502 | &editor_table_info->aid_editor); 503 | assert(bf_status == BF_SUCCESS); 504 | 505 | // Get field-ids for data field 506 | bf_status = bf_rt_data_field_id_with_action_get( 507 | *editor_table, "dst_mac", 508 | editor_table_info->aid_editor, &editor_table_info->did_dst_mac 509 | ); 510 | assert(bf_status == BF_SUCCESS); 511 | bf_status = bf_rt_data_field_id_with_action_get( 512 | *editor_table, "pipr_sidx", 513 | editor_table_info->aid_editor, &editor_table_info->did_pipr_sidx 514 | ); 515 | assert(bf_status == BF_SUCCESS); 516 | } 517 | 518 | static void editor_table_entry_add(const bf_rt_target_t *dev_tgt, 519 | const bf_rt_session_hdl *session, 520 | const bf_rt_table_hdl *editor_table, 521 | editor_table_info_t *editor_table_info, 522 | editor_table_entry_t *editor_entry) { 523 | bf_status_t bf_status; 524 | 525 | // Reset key before use 526 | bf_rt_table_key_reset(editor_table, &editor_table_info->key); 527 | 528 | // Fill in the Key object 529 | bf_status = bf_rt_key_field_set_value(editor_table_info->key, 530 | editor_table_info->kid_egress_port, 531 | editor_entry->egress_port); 532 | assert(bf_status == BF_SUCCESS); 533 | 534 | // Reset data before use 535 | bf_rt_table_action_data_reset(editor_table, 536 | editor_table_info->aid_editor, 537 | &editor_table_info->data); 538 | 539 | // Fill in the Data object 540 | bf_status = bf_rt_data_field_set_value(editor_table_info->data, 541 | editor_table_info->did_dst_mac, 542 | editor_entry->dst_mac); 543 | assert(bf_status == BF_SUCCESS); 544 | bf_status = bf_rt_data_field_set_value(editor_table_info->data, 545 | editor_table_info->did_pipr_sidx, 546 | editor_entry->pipr_sidx); 547 | assert(bf_status == BF_SUCCESS); 548 | 549 | // Call table entry add API 550 | bf_status = bf_rt_table_entry_add(editor_table, session, dev_tgt, 551 | editor_table_info->key, 552 | editor_table_info->data); 553 | assert(bf_status == BF_SUCCESS); 554 | bf_status = bf_rt_session_complete_operations(session); 555 | assert(bf_status == BF_SUCCESS); 556 | } 557 | 558 | static void editor_table_deploy(const bf_rt_target_t *dev_tgt, 559 | const bf_rt_info_hdl *bfrt_info, 560 | const bf_rt_session_hdl *session, 561 | const switch_port_t *forward_list, 562 | const uint8_t forward_count) { 563 | bf_status_t bf_status; 564 | const bf_rt_table_hdl *editor_table = NULL; 565 | editor_table_info_t editor_table_info; 566 | 567 | // Set up the editor table 568 | editor_table_setup(bfrt_info, &editor_table, &editor_table_info); 569 | printf("Table of editor is set up correctly!\n"); 570 | 571 | // Add editor entries 572 | for (unsigned int idx = 0; idx < forward_count; idx++) { 573 | editor_table_entry_t editor_entry; 574 | bf_status = bf_pm_port_str_to_dev_port_get( 575 | dev_tgt->dev_id, 576 | (char *)forward_list[idx].fp_port, &editor_entry.egress_port 577 | ); 578 | assert(bf_status == BF_SUCCESS); 579 | editor_entry.dst_mac = forward_list[idx].dst_mac; 580 | editor_entry.pipr_sidx = idx << IP_RANGE_INDEX_PER_PORT_BITS; 581 | editor_table_entry_add(dev_tgt, session, editor_table, 582 | &editor_table_info, &editor_entry); 583 | printf("Add entry for probe packets to port %s " 584 | "with dmac "MAC_FMT" and pipr_sidx 0x%x\n", 585 | forward_list[idx].fp_port, 586 | MAC_DATA(forward_list[idx].dst_mac), editor_entry.pipr_sidx); 587 | } 588 | } 589 | 590 | static void resultdb_table_setup(const bf_rt_info_hdl *bfrt_info, 591 | uint32_t resultdb_idx, 592 | const bf_rt_table_hdl **target_table, 593 | const bf_rt_table_hdl **result_table, 594 | resultdb_table_info_t *target_table_info, 595 | resultdb_table_info_t *result_table_info) { 596 | bf_status_t bf_status; 597 | 598 | char table_name[256]; 599 | char action_name[256]; 600 | 601 | // Set up target table 602 | sprintf(table_name, 603 | "SwitchEgress.te_resultdb_%u_target_accessor", resultdb_idx); 604 | sprintf(action_name, 605 | "SwitchEgress.ae_update_resultdb_%u_target", resultdb_idx); 606 | 607 | // Get table object from name 608 | bf_status = bf_rt_table_from_name_get(bfrt_info, table_name, target_table); 609 | assert(bf_status == BF_SUCCESS); 610 | 611 | // Allocate key and data once, and use reset across different uses 612 | bf_status = bf_rt_table_key_allocate(*target_table, 613 | &target_table_info->key); 614 | assert(bf_status == BF_SUCCESS); 615 | bf_status = bf_rt_table_data_allocate(*target_table, 616 | &target_table_info->data); 617 | assert(bf_status == BF_SUCCESS); 618 | 619 | // Get field-ids for key field 620 | bf_status = bf_rt_key_field_id_get(*target_table, 621 | "eg_md.bridged.resp_pkt_count", 622 | &target_table_info->kid_resp_pkt_count); 623 | assert(bf_status == BF_SUCCESS); 624 | 625 | // Get action Ids 626 | bf_status = bf_rt_action_name_to_id( 627 | *target_table, action_name, &target_table_info->aid_update_resultdb 628 | ); 629 | assert(bf_status == BF_SUCCESS); 630 | 631 | // Set up result table 632 | sprintf(table_name, 633 | "SwitchEgress.te_resultdb_%u_result_accessor", resultdb_idx); 634 | sprintf(action_name, 635 | "SwitchEgress.ae_update_resultdb_%u_result", resultdb_idx); 636 | // Get table object from name 637 | bf_status = bf_rt_table_from_name_get(bfrt_info, table_name, result_table); 638 | assert(bf_status == BF_SUCCESS); 639 | 640 | // Allocate key and data once, and use reset across different uses 641 | bf_status = bf_rt_table_key_allocate(*result_table, 642 | &result_table_info->key); 643 | assert(bf_status == BF_SUCCESS); 644 | bf_status = bf_rt_table_data_allocate(*result_table, 645 | &result_table_info->data); 646 | assert(bf_status == BF_SUCCESS); 647 | 648 | // Get field-ids for key field 649 | bf_status = bf_rt_key_field_id_get(*result_table, 650 | "eg_md.bridged.resp_pkt_count", 651 | &result_table_info->kid_resp_pkt_count); 652 | assert(bf_status == BF_SUCCESS); 653 | 654 | 655 | // Get action Ids 656 | bf_status = bf_rt_action_name_to_id( 657 | *result_table, action_name, &result_table_info->aid_update_resultdb 658 | ); 659 | assert(bf_status == BF_SUCCESS); 660 | } 661 | 662 | static void resultdb_table_entry_add(const bf_rt_target_t *dev_tgt, 663 | const bf_rt_session_hdl *session, 664 | uint32_t resultdb_idx, 665 | const bf_rt_table_hdl *resultdb_table, 666 | resultdb_table_info_t *resultdb_table_info, 667 | resultdb_table_entry_t *resultdb_entry) { 668 | bf_status_t bf_status; 669 | 670 | // Reset key before use 671 | bf_rt_table_key_reset(resultdb_table, &resultdb_table_info->key); 672 | 673 | // Fill in the Key object 674 | bf_status = bf_rt_key_field_set_value( 675 | resultdb_table_info->key, 676 | resultdb_table_info->kid_resp_pkt_count, resultdb_entry->resp_pkt_count 677 | ); 678 | assert(bf_status == BF_SUCCESS); 679 | 680 | bf_rt_table_action_data_reset(resultdb_table, 681 | resultdb_table_info->aid_update_resultdb, 682 | &resultdb_table_info->data); 683 | assert(bf_status == BF_SUCCESS); 684 | 685 | // Call table entry add API 686 | bf_status = bf_rt_table_entry_add(resultdb_table, session, dev_tgt, 687 | resultdb_table_info->key, 688 | resultdb_table_info->data); 689 | assert(bf_status == BF_SUCCESS); 690 | bf_rt_session_complete_operations(session); 691 | } 692 | 693 | static void resultdb_table_deploy(const bf_rt_target_t *dev_tgt, 694 | const bf_rt_info_hdl *bfrt_info, 695 | const bf_rt_session_hdl *session) { 696 | bf_status_t bf_status; 697 | const bf_rt_table_hdl *resultdb_target_tables[RESULT_DATABASE_SIZE]; 698 | const bf_rt_table_hdl *resultdb_result_tables[RESULT_DATABASE_SIZE]; 699 | resultdb_table_info_t resultdb_target_tables_info[RESULT_DATABASE_SIZE]; 700 | resultdb_table_info_t resultdb_result_tables_info[RESULT_DATABASE_SIZE]; 701 | 702 | for (int db_idx = 0; db_idx < RESULT_DATABASE_SIZE; db_idx++){ 703 | // Set up resultdb tables 704 | resultdb_table_setup(bfrt_info, db_idx, 705 | &resultdb_target_tables[db_idx], 706 | &resultdb_result_tables[db_idx], 707 | &resultdb_target_tables_info[db_idx], 708 | &resultdb_result_tables_info[db_idx]); 709 | printf("Tables of result database %u is set up correctly!\n", db_idx); 710 | 711 | resultdb_table_entry_t resultdb_table_entry = { 712 | .resp_pkt_count = db_idx 713 | }; 714 | resultdb_table_entry_add(dev_tgt, session, db_idx, 715 | resultdb_target_tables[db_idx], 716 | &resultdb_target_tables_info[db_idx], 717 | &resultdb_table_entry); 718 | printf("Add entry to update result database %u's target!\n", db_idx); 719 | resultdb_table_entry_add(dev_tgt, session, db_idx, 720 | resultdb_result_tables[db_idx], 721 | &resultdb_result_tables_info[db_idx], 722 | &resultdb_table_entry); 723 | printf("Add entry to update result database %u's result!\n", db_idx); 724 | } 725 | } 726 | 727 | static void register_setup(const bf_rt_info_hdl *bfrt_info, 728 | const char *reg_name, 729 | const char *value_field_name, 730 | const bf_rt_table_hdl **reg, 731 | register_info_t *reg_info) { 732 | bf_status_t bf_status; 733 | char reg_value_field_name[64]; 734 | 735 | // Get table object from name 736 | bf_status = bf_rt_table_from_name_get(bfrt_info, reg_name, reg); 737 | assert(bf_status == BF_SUCCESS); 738 | 739 | // Allocate key and data once, and use reset across different uses 740 | bf_status = bf_rt_table_key_allocate(*reg, ®_info->key); 741 | assert(bf_status == BF_SUCCESS); 742 | bf_status = bf_rt_table_data_allocate(*reg, ®_info->data); 743 | assert(bf_status == BF_SUCCESS); 744 | 745 | // Get field-ids for key field 746 | bf_status = bf_rt_key_field_id_get(*reg, "$REGISTER_INDEX", 747 | ®_info->kid_register_index); 748 | assert(bf_status == BF_SUCCESS); 749 | 750 | // Get field-ids for data field 751 | strcpy(reg_value_field_name, reg_name); 752 | if (value_field_name == NULL) { 753 | strcat(reg_value_field_name, ".f1"); 754 | } 755 | else { 756 | strcat(reg_value_field_name, "."); 757 | strcat(reg_value_field_name, value_field_name); 758 | } 759 | bf_status = bf_rt_data_field_id_get(*reg, reg_value_field_name, 760 | ®_info->did_value); 761 | assert(bf_status == BF_SUCCESS); 762 | } 763 | 764 | static void register_write(const bf_rt_target_t *dev_tgt, 765 | const bf_rt_session_hdl *session, 766 | const bf_rt_table_hdl *reg, 767 | register_info_t *reg_info, 768 | register_entry_t *reg_entry) { 769 | bf_status_t bf_status; 770 | 771 | // Reset key and data before use 772 | bf_rt_table_key_reset(reg, ®_info->key); 773 | bf_rt_table_data_reset(reg, ®_info->data); 774 | 775 | // Fill in the Key and Data object 776 | bf_status = bf_rt_key_field_set_value(reg_info->key, 777 | reg_info->kid_register_index, 778 | reg_entry->register_index); 779 | assert(bf_status == BF_SUCCESS); 780 | bf_status = bf_rt_data_field_set_value(reg_info->data, 781 | reg_info->did_value, 782 | reg_entry->value); 783 | assert(bf_status == BF_SUCCESS); 784 | 785 | // Call table entry add API 786 | bf_status = bf_rt_table_entry_add(reg, session, dev_tgt, 787 | reg_info->key, reg_info->data); 788 | assert(bf_status == BF_SUCCESS); 789 | bf_status = bf_rt_session_complete_operations(session); 790 | assert(bf_status == BF_SUCCESS); 791 | } 792 | 793 | static void register_write_no_wait(const bf_rt_target_t *dev_tgt, 794 | const bf_rt_session_hdl *session, 795 | const bf_rt_table_hdl *reg, 796 | register_info_t *reg_info, 797 | register_entry_t *reg_entry) { 798 | bf_status_t bf_status; 799 | 800 | // Reset key and data before use 801 | bf_rt_table_key_reset(reg, ®_info->key); 802 | bf_rt_table_data_reset(reg, ®_info->data); 803 | 804 | // Fill in the Key and Data object 805 | bf_status = bf_rt_key_field_set_value(reg_info->key, 806 | reg_info->kid_register_index, 807 | reg_entry->register_index); 808 | assert(bf_status == BF_SUCCESS); 809 | bf_status = bf_rt_data_field_set_value(reg_info->data, 810 | reg_info->did_value, 811 | reg_entry->value); 812 | assert(bf_status == BF_SUCCESS); 813 | 814 | // Call table entry add API 815 | bf_status = bf_rt_table_entry_add(reg, session, dev_tgt, 816 | reg_info->key, reg_info->data); 817 | assert(bf_status == BF_SUCCESS); 818 | // bf_status = bf_rt_session_complete_operations(session); 819 | // assert(bf_status == BF_SUCCESS); 820 | } 821 | 822 | static void register_read(const bf_rt_target_t *dev_tgt, 823 | const bf_rt_session_hdl *session, 824 | const bf_rt_table_hdl *reg, 825 | register_info_t *reg_info, 826 | register_entry_t *reg_entry) { 827 | bf_status_t bf_status; 828 | 829 | // Reset key and data before use 830 | bf_rt_table_key_reset(reg, ®_info->key); 831 | bf_rt_table_data_reset(reg, ®_info->data); 832 | 833 | // Fill in the Key object 834 | bf_status = bf_rt_key_field_set_value(reg_info->key, 835 | reg_info->kid_register_index, 836 | reg_entry->register_index); 837 | assert(bf_status == BF_SUCCESS); 838 | bf_status = bf_rt_data_field_set_value(reg_info->data, 839 | reg_info->did_value, 840 | reg_entry->value); 841 | assert(bf_status == BF_SUCCESS); 842 | 843 | // Call table entry add API 844 | bf_status = bf_rt_table_entry_get(reg, session, dev_tgt, reg_info->key, 845 | reg_info->data, ENTRY_READ_FROM_HW); 846 | assert(bf_status == BF_SUCCESS); 847 | bf_status = bf_rt_session_complete_operations(session); 848 | assert(bf_status == BF_SUCCESS); 849 | 850 | // Get the real values in the Data object 851 | // Notice: I don't know whether bf_rt_data_field_get_value_u64_array works 852 | // fine here, instead bf_rt_data_field_get_value_u64_array. 853 | bf_status = bf_rt_data_field_get_value_u64_array_size( 854 | reg_info->data, reg_info->did_value, ®_entry->value_array_size 855 | ); 856 | assert(bf_status == BF_SUCCESS); 857 | if (reg_entry->value_array) { 858 | free(reg_entry->value_array); 859 | } 860 | reg_entry->value_array = (uint64_t *)malloc 861 | (reg_entry->value_array_size * sizeof(uint64_t)); 862 | bf_status = bf_rt_data_field_get_value_u64_array(reg_info->data, 863 | reg_info->did_value, 864 | reg_entry->value_array); 865 | assert(bf_status == BF_SUCCESS); 866 | } 867 | 868 | static void probe_period_setup(const bf_rt_info_hdl *bfrt_info, 869 | probe_period_t *period_reg) { 870 | // Set up the probe period register 871 | register_setup(bfrt_info, "SwitchIngress.ri_probe_period", 872 | NULL, &period_reg->reg, &period_reg->reg_info); 873 | printf("Register of probe period is set up correctly!\n"); 874 | } 875 | 876 | void probe_period_config(iswitch_t *iswitch, uint32_t probe_period) { 877 | register_entry_t probe_period_entry; 878 | 879 | probe_period_entry.register_index = 0; 880 | probe_period_entry.value = probe_period; 881 | register_write(&iswitch->dev_tgt, iswitch->session, iswitch->period_reg.reg, 882 | &iswitch->period_reg.reg_info, &probe_period_entry); 883 | printf("Register of probe period is set to " 884 | "%d correctly!\n", probe_period_entry.value); 885 | } 886 | 887 | static void probe_port_stride_setup(const bf_rt_info_hdl *bfrt_info, 888 | probe_port_stride_t *stride_reg) { 889 | // Set up the probe port register 890 | register_setup(bfrt_info, "SwitchIngress.ri_probe_port_stride", 891 | NULL, &stride_reg->reg, &stride_reg->reg_info); 892 | printf("Register of probe port stride is set up correctly!\n"); 893 | } 894 | 895 | void probe_port_stride_config(iswitch_t *iswitch, uint16_t probe_port_stride) { 896 | register_entry_t probe_port_stride_entry; 897 | 898 | probe_port_stride_entry.register_index = 0; 899 | probe_port_stride_entry.value = probe_port_stride; 900 | register_write(&iswitch->dev_tgt, iswitch->session, iswitch->stride_reg.reg, 901 | &iswitch->stride_reg.reg_info, &probe_port_stride_entry); 902 | printf("Register of probe port stride is set to " 903 | "%hu correctly!\n", probe_port_stride_entry.value); 904 | } 905 | 906 | static void probe_port_setup(const bf_rt_info_hdl *bfrt_info, 907 | probe_port_t *port_reg) { 908 | // Set up the probe port register 909 | register_setup(bfrt_info, "SwitchEgress.re_probe_port", 910 | "probe_port", &port_reg->reg, &port_reg->reg_info); 911 | printf("Register of probe port is set up correctly!\n"); 912 | } 913 | 914 | void probe_port_config(iswitch_t *iswitch, uint16_t probe_port) { 915 | register_entry_t probe_port_entry; 916 | 917 | probe_port_entry.register_index = 0; 918 | probe_port_entry.value = probe_port; 919 | register_write(&iswitch->dev_tgt, iswitch->session, iswitch->port_reg.reg, 920 | &iswitch->port_reg.reg_info, &probe_port_entry); 921 | printf("Register of probe port is set to " 922 | "%hu correctly!\n", probe_port_entry.value); 923 | } 924 | 925 | static void probe_ip_range_table_setup(const bf_rt_info_hdl *bfrt_info, 926 | probe_ip_range_table_t *pipr_table_t0, 927 | probe_ip_range_table_t *pipr_table_t1) { 928 | // Set up the probe ip range registers 929 | register_setup(bfrt_info, "SwitchEgress.re_pipr_t0_pidx", NULL, 930 | &pipr_table_t0->pipr_pidx_reg, 931 | &pipr_table_t0->pipr_pidx_reg_info); 932 | register_setup(bfrt_info, "SwitchEgress.re_pipr_t1_pidx", NULL, 933 | &pipr_table_t1->pipr_pidx_reg, 934 | &pipr_table_t1->pipr_pidx_reg_info); 935 | register_setup(bfrt_info, "SwitchEgress.re_pipr_t0_start", NULL, 936 | &pipr_table_t0->pipr_start_reg, 937 | &pipr_table_t0->pipr_start_reg_info); 938 | register_setup(bfrt_info, "SwitchEgress.re_pipr_t1_start", NULL, 939 | &pipr_table_t1->pipr_start_reg, 940 | &pipr_table_t1->pipr_start_reg_info); 941 | register_setup(bfrt_info, "SwitchEgress.re_pipr_t0_end", NULL, 942 | &pipr_table_t0->pipr_end_reg, 943 | &pipr_table_t0->pipr_end_reg_info); 944 | register_setup(bfrt_info, "SwitchEgress.re_pipr_t1_end", NULL, 945 | &pipr_table_t1->pipr_end_reg, 946 | &pipr_table_t1->pipr_end_reg_info); 947 | #if __IP_TYPE__ == 6 948 | register_setup(bfrt_info, "SwitchEgress.re_pip_prefix_1", NULL, 949 | &pipr_table->pip_prefix_1_reg, 950 | &pipr_table->pip_prefix_1_reg_info); 951 | register_setup(bfrt_info, "SwitchEgress.re_pip_prefix_2", NULL, 952 | &pipr_table->pip_prefix_2_reg, 953 | &pipr_table->pip_prefix_2_reg_info); 954 | register_setup(bfrt_info, "SwitchEgress.re_pip_prefix_3", NULL, 955 | &pipr_table->pip_prefix_3_reg, 956 | &pipr_table->pip_prefix_3_reg_info); 957 | #endif 958 | printf("Registers of pipr (probe ip range) are set up correctly!\n"); 959 | } 960 | 961 | void probe_ip_range_table_reset(iswitch_t *iswitch, const uint8_t probe_table) { 962 | probe_ip_range_table_t *pipr_table; 963 | register_entry_t pipr_pidx_entry; 964 | 965 | if (probe_table == 0) { 966 | pipr_table = &iswitch->pipr_table_t0; 967 | } 968 | else { 969 | pipr_table = &iswitch->pipr_table_t1; 970 | } 971 | 972 | for (uint16_t idx = 0; idx < (1 << IP_RANGE_INDEX_PORT_BITS); idx++) { 973 | pipr_pidx_entry.register_index = idx; 974 | pipr_pidx_entry.value = 0; 975 | register_write(&iswitch->dev_tgt, iswitch->session, 976 | pipr_table->pipr_pidx_reg, 977 | &pipr_table->pipr_pidx_reg_info, &pipr_pidx_entry); 978 | } 979 | } 980 | 981 | void probe_ip_range_table_install(iswitch_t *iswitch, 982 | const uint8_t probe_table, 983 | const uint32_t pipr_idx, 984 | const probe_entry_t *probe_entry) { 985 | probe_ip_range_table_t *pipr_table; 986 | register_entry_t pipr_entry; 987 | 988 | if (probe_table == 0) { 989 | pipr_table = &iswitch->pipr_table_t0; 990 | } 991 | else { 992 | pipr_table = &iswitch->pipr_table_t1; 993 | } 994 | 995 | // Write probe ip range 996 | pipr_entry.register_index = pipr_idx; 997 | // Register re_pipr_start 998 | pipr_entry.value = probe_entry->start; 999 | register_write(&iswitch->dev_tgt, iswitch->session, 1000 | pipr_table->pipr_start_reg, 1001 | &pipr_table->pipr_start_reg_info, &pipr_entry); 1002 | // Register re_pipr_end 1003 | pipr_entry.value = probe_entry->end; 1004 | register_write(&iswitch->dev_tgt, iswitch->session, 1005 | pipr_table->pipr_end_reg, 1006 | &pipr_table->pipr_end_reg_info, &pipr_entry); 1007 | #if __IP_TYPE__ == 6 1008 | // TODO: Next codes need to be updated 1009 | // Register re_pip_prefix_1 1010 | pipr_entry.value = 0xfe800000; 1011 | register_write(&iswitch->dev_tgt, iswitch->session, 1012 | pipr_table->pip_prefix_1_reg, 1013 | &pipr_table->pip_prefix_1_reg_info, &pipr_entry); 1014 | // Register re_pip_prefix_2 1015 | pipr_entry.value = 0x00000000; 1016 | register_write(&iswitch->dev_tgt, iswitch->session, 1017 | pipr_table->pip_prefix_2_reg, 1018 | &pipr_table->pip_prefix_2_reg_info, &pipr_entry); 1019 | // Register re_pip_prefix_3 1020 | pipr_entry.value = 0x6a91d0ff; 1021 | register_write(&iswitch->dev_tgt, iswitch->session, 1022 | pipr_table->pip_prefix_3_reg, 1023 | &pipr_table->pip_prefix_3_reg_info, &pipr_entry); 1024 | #endif 1025 | // printf("Registers of pipr (probe ip range) are set successfully!\n"); 1026 | } 1027 | 1028 | void probe_ip_range_table_install_batch(iswitch_t *iswitch, 1029 | const uint8_t probe_table, 1030 | const uint32_t pipr_idx_start, 1031 | const uint32_t batch_size, 1032 | const probe_entry_t *probe_entries) { 1033 | bf_status_t bf_status; 1034 | probe_ip_range_table_t *pipr_table; 1035 | register_entry_t pipr_entry; 1036 | 1037 | if (probe_table == 0) { 1038 | pipr_table = &iswitch->pipr_table_t0; 1039 | } 1040 | else { 1041 | pipr_table = &iswitch->pipr_table_t1; 1042 | } 1043 | 1044 | // Start batch operation 1045 | bf_status = bf_rt_begin_batch(iswitch->session); 1046 | assert(bf_status == BF_SUCCESS); 1047 | 1048 | // Write probe ip ranges 1049 | for (uint32_t idx = 0; idx < batch_size; idx++) { 1050 | pipr_entry.register_index = pipr_idx_start + idx; 1051 | // Register re_pipr_start 1052 | pipr_entry.value = probe_entries[idx].start; 1053 | register_write_no_wait(&iswitch->dev_tgt, iswitch->session, 1054 | pipr_table->pipr_start_reg, 1055 | &pipr_table->pipr_start_reg_info, &pipr_entry); 1056 | // Register re_pipr_end 1057 | pipr_entry.value = probe_entries[idx].end; 1058 | register_write_no_wait(&iswitch->dev_tgt, iswitch->session, 1059 | pipr_table->pipr_end_reg, 1060 | &pipr_table->pipr_end_reg_info, &pipr_entry); 1061 | } 1062 | 1063 | bf_status = bf_rt_end_batch(iswitch->session, true); 1064 | assert(bf_status == BF_SUCCESS); 1065 | 1066 | //TODO: handle IPv6 1067 | } 1068 | 1069 | // void probe_ip_range_table_fetch(iswitch_t *iswitch, 1070 | // const uint8_t probe_table, 1071 | // const uint32_t pipr_idx) { 1072 | // bf_status_t bf_status; 1073 | // probe_ip_range_table_t *pipr_table; 1074 | // register_entry_t pipr_entry; 1075 | 1076 | // if (probe_table == 0) { 1077 | // pipr_table = &iswitch->pipr_table_t0; 1078 | // } 1079 | // else { 1080 | // pipr_table = &iswitch->pipr_table_t1; 1081 | // } 1082 | 1083 | // pipr_entry.register_index = pipr_idx; 1084 | // printf("Debug: pipr_idx %u, ", pipr_idx); 1085 | // register_read(&iswitch->dev_tgt, iswitch->session, 1086 | // pipr_table->pipr_start_reg, 1087 | // &pipr_table->pipr_start_reg_info, &pipr_entry); 1088 | // printf("start %lx, ", pipr_entry.value_array[2]); 1089 | // register_read(&iswitch->dev_tgt, iswitch->session, 1090 | // pipr_table->pipr_end_reg, 1091 | // &pipr_table->pipr_end_reg_info, &pipr_entry); 1092 | // printf("end %lx\n", pipr_entry.value_array[2]); 1093 | // } 1094 | 1095 | int launch_iswitch(iswitch_t *iswitch, 1096 | const switch_port_t *forward_list, 1097 | const uint8_t forward_count) { 1098 | bf_switchd_context_t *switchd_ctx; 1099 | bf_rt_target_t *dev_tgt = &iswitch->dev_tgt; 1100 | const bf_rt_info_hdl *bfrt_info = NULL; 1101 | bf_rt_session_hdl **session = &iswitch->session; 1102 | 1103 | dev_tgt->dev_id = 0; 1104 | dev_tgt->pipe_id = BF_DEV_PIPE_ALL; 1105 | 1106 | // Initialize and set the bf_switchd 1107 | switchd_ctx = (bf_switchd_context_t *) 1108 | calloc(1, sizeof(bf_switchd_context_t)); 1109 | if (switchd_ctx == NULL) { 1110 | printf("Cannot allocate switchd context\n"); 1111 | return -1; 1112 | } 1113 | switchd_setup(switchd_ctx); 1114 | 1115 | // Get BfRtInfo and create the bf_runtime session 1116 | bfrt_setup(dev_tgt, &bfrt_info, session); 1117 | 1118 | // Set up the forward ports of the switch 1119 | port_setup(dev_tgt, forward_list, forward_count); 1120 | 1121 | // Set up the result server port of the switch 1122 | result_server_port_setup(dev_tgt, RESULT_SERVER_PORT); 1123 | 1124 | // Set up the result server multicat 1125 | result_server_multicast_setup(dev_tgt, bfrt_info); 1126 | 1127 | // Set up the update notifying mirror 1128 | update_notifying_mirror_setup(dev_tgt); 1129 | 1130 | // Set up and add entries for the forward table 1131 | forward_table_deploy(dev_tgt, bfrt_info, *session, 1132 | forward_list, forward_count); 1133 | 1134 | // Set up and add entries for the active/inactive handler table 1135 | probe_resp_handler_table_deploy(dev_tgt, bfrt_info, *session); 1136 | 1137 | // Set up and add entries for the editor table 1138 | editor_table_deploy(dev_tgt, bfrt_info, *session, 1139 | forward_list, forward_count); 1140 | 1141 | // Set up and add entries for the response vector tables 1142 | resultdb_table_deploy(dev_tgt, bfrt_info, *session); 1143 | 1144 | // Set up the probe period register 1145 | probe_period_setup(bfrt_info, &iswitch->period_reg); 1146 | 1147 | // Set up the probe port stride register 1148 | probe_port_stride_setup(bfrt_info, &iswitch->stride_reg); 1149 | 1150 | // Set up the probe port register 1151 | probe_port_setup(bfrt_info, &iswitch->port_reg); 1152 | 1153 | // Set up the probe ip range registers 1154 | probe_ip_range_table_setup(bfrt_info, 1155 | &iswitch->pipr_table_t0, 1156 | &iswitch->pipr_table_t1); 1157 | 1158 | return 0; 1159 | } --------------------------------------------------------------------------------