├── topo.png ├── northbound ├── cmdline │ ├── cmds.h │ ├── Makefile │ └── cmds.c └── grpc │ ├── vrg_grpc_server.h │ ├── vrg_grpc_client.h │ ├── Makefile │ ├── vrg_grpc_server.cpp │ ├── vrg_node_grpc.h │ ├── vrg_node.proto │ ├── vrg_grpc_client.cpp │ └── vrg_node_grpc.cpp ├── src ├── timer.h ├── dp_flow.h ├── trace.c ├── main.c ├── trace.h ├── dp.h ├── config.h ├── dhcpd │ ├── dhcpd.h │ ├── dhcp_fsm.h │ ├── dhcp_codec.h │ ├── dhcpd.c │ ├── dhcp_fsm.c │ └── dhcp_codec.c ├── timer.c ├── init.h ├── dbg.h ├── pppd │ ├── nat.c │ ├── codec.h │ ├── fsm.h │ ├── pppd.h │ ├── header.h │ ├── nat.h │ └── pppd.c ├── protocol.h ├── uilts.c ├── ethtool.c ├── dp_flow.c ├── utils.h ├── vrg.h ├── config.c ├── init.c ├── dbg.c ├── vrg.c └── dp_codec.h ├── .gitignore ├── .gitmodules ├── .dockerignore ├── unit_test ├── test.h ├── test.c ├── Makefile └── pppd │ └── codec_test.c ├── config.cfg ├── .github ├── dependabot.yml └── workflows │ ├── ci.yml │ └── release.yml ├── Dockerfile ├── boot.sh ├── LICENSE ├── essensials.sh ├── Makefile └── README.md /topo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w180112/vRG_DPDK/HEAD/topo.png -------------------------------------------------------------------------------- /northbound/cmdline/cmds.h: -------------------------------------------------------------------------------- 1 | #ifndef _CMDS_H_ 2 | #define _CMDS_H_ 3 | 4 | #include 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /src/timer.h: -------------------------------------------------------------------------------- 1 | #ifndef _TIMER_H_ 2 | #define _TIMER_H_ 3 | 4 | int timer_loop(__rte_unused void *arg); 5 | 6 | #endif -------------------------------------------------------------------------------- /src/dp_flow.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern struct rte_flow *generate_flow(U16 port_id, U16 rx_q, struct rte_flow_error *error); -------------------------------------------------------------------------------- /src/trace.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include "trace.h" 5 | 6 | RTE_TRACE_POINT_REGISTER(rte_ethdev_trace_rx_pkt, lib.ethdev.rx.pkt) -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/.DS_Store 2 | .vscode 3 | *.log 4 | build 5 | **/*.o 6 | **/vrg 7 | **/vrg_northbound 8 | **/.libs 9 | unit_test/unit-tester 10 | **/vrg_cli 11 | **/libvrg_northbound.a 12 | **/*.pb.* 13 | src/version.h -------------------------------------------------------------------------------- /northbound/grpc/vrg_grpc_server.h: -------------------------------------------------------------------------------- 1 | #ifndef VRG_GRPC_SERVER_H 2 | #define VRG_GRPC_SERVER_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | void vrg_grpc_server_run(void *arg); 9 | 10 | #ifdef __cplusplus 11 | } 12 | #endif 13 | 14 | #endif // VRG_GRPC_SERVER_H -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "vrg.h" 4 | 5 | int main(int argc, char **argv) 6 | { 7 | if (argc < 5) { 8 | puts("Too less parameter."); 9 | puts("Type vrg "); 10 | return ERROR; 11 | } 12 | return vrg_start(argc, argv); 13 | } -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/libutil"] 2 | path = lib/libutil 3 | url = https://github.com/w180112/libutil.git 4 | [submodule "lib/dpdk-kmods"] 5 | path = lib/dpdk-kmods 6 | url = https://dpdk.org/git/dpdk-kmods 7 | branch = main 8 | [submodule "lib/dpdk"] 9 | path = lib/dpdk 10 | url = git://dpdk.org/dpdk-stable 11 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | # macOS junk files 2 | **/.DS_Store 3 | 4 | # IDE / editor configs 5 | .vscode 6 | 7 | # Logs 8 | *.log 9 | 10 | # Build outputs 11 | build 12 | lib/** 13 | **/*.o 14 | **/vrg 15 | **/vrg_northbound 16 | **/.libs 17 | unit_test/unit-tester 18 | **/vrg_cli 19 | **/libvrg_northbound.a 20 | **/*.pb.* 21 | 22 | # Generated source 23 | src/version.h 24 | -------------------------------------------------------------------------------- /unit_test/test.h: -------------------------------------------------------------------------------- 1 | #ifndef _TEST_H_ 2 | #define _TEST_H_ 3 | 4 | void test_build_padi(); 5 | void test_build_padr(); 6 | void test_build_padt(); 7 | void test_build_config_request(); 8 | void test_build_config_ack(); 9 | void test_build_terminate_request(); 10 | void test_build_config_nak_rej(); 11 | void test_build_terminate_ack(); 12 | void test_build_echo_reply(); 13 | void test_build_auth_request_pap(); 14 | void test_build_auth_ack_pap(); 15 | 16 | #endif -------------------------------------------------------------------------------- /config.cfg: -------------------------------------------------------------------------------- 1 | # vRG system configuration 2 | # It uses libconfig to parse config file 3 | 4 | # vRG user count 5 | UserCount = 20; 6 | 7 | # vRG acceptable vlan id 8 | BaseVlan = 2; 9 | 10 | # vRG loglvl 11 | Loglvl = "DBG"; 12 | LogPath = "/var/log/vrg/vrg.log"; 13 | 14 | # non-vlan mode 15 | NonVlanMode = 0; 16 | 17 | # vRG default gateway ip 18 | DefaultGateway = "192.168.2.1"; 19 | 20 | NodeGrpcUnixSocket = "unix:///var/run/vrg/vrg.sock"; 21 | NodeGrpcPort = "50051"; -------------------------------------------------------------------------------- /src/trace.h: -------------------------------------------------------------------------------- 1 | /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ 2 | TRACE.H 3 | 4 | Designed by THE on JUN 11, 2019 5 | /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/ 6 | 7 | #ifndef _TRACE_H_ 8 | #define _TRACE_H_ 9 | 10 | #include 11 | #include 12 | 13 | RTE_TRACE_POINT_FP( 14 | rte_ethdev_trace_rx_pkt, 15 | RTE_TRACE_POINT_ARGS(U8 *payload), 16 | rte_trace_point_emit_ptr(payload); 17 | ) 18 | 19 | #endif -------------------------------------------------------------------------------- /src/dp.h: -------------------------------------------------------------------------------- 1 | /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ 2 | DP.H 3 | 4 | Designed by THE on JAN 21, 2021 5 | /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/ 6 | 7 | #ifndef _DP_H_ 8 | #define _DP_H_ 9 | 10 | #include "vrg.h" 11 | 12 | void drv_xmit(VRG_t *vrg_ccb, U8 *mu, U16 mulen); 13 | int wan_recvd(void *arg); 14 | int uplink(void *arg); 15 | int downlink(void *arg); 16 | int gateway(void *arg); 17 | int lan_recvd(void *arg); 18 | int PORT_INIT(VRG_t *vrg_ccb, U16 port); 19 | 20 | #endif -------------------------------------------------------------------------------- /src/config.h: -------------------------------------------------------------------------------- 1 | /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ 2 | CONFIG.H 3 | 4 | Designed by THE on Sep 15, 2023 5 | /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/ 6 | 7 | #ifndef _CONFIG_H_ 8 | #define _CONFIG_H_ 9 | 10 | #include "vrg.h" 11 | 12 | struct vrg_config { 13 | char unix_sock_path[256]; 14 | char node_grpc_ip_port[256]; 15 | char log_path[256]; 16 | }; 17 | 18 | STATUS parse_config(const char *config_path, VRG_t *vrg_ccb, struct vrg_config *vrg_cfg); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /src/dhcpd/dhcpd.h: -------------------------------------------------------------------------------- 1 | /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ 2 | DHCPD.H 3 | 4 | Designed by THE on MAR 21, 2021 5 | /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/ 6 | 7 | #ifndef _DHCPD_H_ 8 | #define _DHCPD_H_ 9 | 10 | #include 11 | #include "../vrg.h" 12 | 13 | int dhcpd(struct rte_mbuf *single_pkt, struct rte_ether_hdr *eth_hdr, vlan_header_t *vlan_header, struct rte_ipv4_hdr *ip_hdr, struct rte_udp_hdr *udp_hdr, U16 user_index); 14 | STATUS dhcp_init(void *ccb); 15 | 16 | #endif -------------------------------------------------------------------------------- /northbound/grpc/vrg_grpc_client.h: -------------------------------------------------------------------------------- 1 | #ifndef VRG_GRPC_SERVER_H 2 | #define VRG_GRPC_CLIENT_H 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | void vrg_grpc_client_connect(char *server_address); 11 | void vrg_grpc_hsi_connect(U8 user_id); 12 | void vrg_grpc_hsi_disconnect(U8 user_id, bool force); 13 | void vrg_grpc_dhcp_server_start(U8 user_id); 14 | void vrg_grpc_dhcp_server_stop(U8 user_id); 15 | void vrg_grpc_get_system_info(); 16 | void vrg_grpc_get_hsi_info(); 17 | void vrg_grpc_get_dhcp_info(); 18 | 19 | #ifdef __cplusplus 20 | } 21 | #endif 22 | 23 | #endif // VRG_GRPC_CLIENT_H -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "gitsubmodule" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | commit-message: 8 | prefix: "chore: " 9 | target-branch: "master" 10 | - package-ecosystem: "docker" 11 | directory: "/" 12 | schedule: 13 | interval: "weekly" 14 | commit-message: 15 | prefix: "chore: " 16 | target-branch: "master" 17 | - package-ecosystem: "github-actions" 18 | directory: "/" 19 | schedule: 20 | interval: "weekly" 21 | commit-message: 22 | prefix: "chore: " 23 | target-branch: "master" -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: vRG ci 2 | on: 3 | push: 4 | branches: 5 | - master 6 | - ci-dev 7 | pull_request: 8 | branches: [ "master" ] 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v5 15 | - run: sudo ${{ github.workspace }}/essensials.sh 16 | - run: sudo ${{ github.workspace }}/boot.sh 17 | - run: sudo docker build --no-cache -t vrg:latest . 18 | test: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v5 22 | - run: sudo ${{ github.workspace }}/essensials.sh 23 | - run: sudo ${{ github.workspace }}/boot.sh 24 | - run: cd ${{ github.workspace }} && sudo make test -------------------------------------------------------------------------------- /src/timer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #define TIMER_RESOLUTION_CYCLES 20000000ULL /* around 10ms at 2 Ghz */ 18 | 19 | __rte_noreturn int timer_loop(__rte_unused void *arg) 20 | { 21 | uint64_t prev_tsc = 0, cur_tsc, diff_tsc; 22 | 23 | for(;;) { 24 | cur_tsc = rte_rdtsc(); 25 | diff_tsc = cur_tsc - prev_tsc; 26 | if (diff_tsc > TIMER_RESOLUTION_CYCLES) { 27 | rte_timer_manage(); 28 | prev_tsc = cur_tsc; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/init.h: -------------------------------------------------------------------------------- 1 | /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ 2 | init.h 3 | 4 | Initiation of vRG 5 | 6 | Designed by THE on Jan 26, 2021 7 | /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/ 8 | #include 9 | #include 10 | #include "vrg.h" 11 | #include "pppd/codec.h" 12 | 13 | #ifndef _INIT_H_ 14 | #define _INIT_H_ 15 | 16 | #define PORT_AMOUNT 2 17 | 18 | #define MLX5 1 19 | #define IXGBE 2 20 | #define I40E 3 21 | #define VMXNET3 4 22 | #define IXGBEVF 5 23 | #define I40EVF 6 24 | 25 | extern int sys_init(VRG_t *vrg_ccb); 26 | 27 | extern struct rte_mempool *direct_pool[PORT_AMOUNT]; 28 | extern struct rte_mempool *indirect_pool[PORT_AMOUNT]; 29 | extern struct rte_ring *rte_ring, *gateway_q, *uplink_q, *downlink_q; 30 | //extern struct rte_mempool *mbuf_pool; 31 | 32 | #endif -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG BUILDER_IMAGE=ubuntu:24.04 2 | ARG RUNTIME_IMAGE=ubuntu:24.04 3 | 4 | FROM ${BUILDER_IMAGE} as builder 5 | LABEL maintainer="w180112@gmail.com" 6 | USER root 7 | 8 | ADD . /vrg 9 | 10 | RUN /vrg/essensials.sh \ 11 | && /vrg/boot.sh 12 | 13 | # ---- Runtime Stage ---- 14 | ARG RUNTIME_IMAGE=ubuntu:24.04 15 | FROM ${RUNTIME_IMAGE} as runtime 16 | USER root 17 | 18 | WORKDIR /vrg 19 | 20 | COPY --from=builder /etc/vrg/ /etc/vrg/ 21 | COPY --from=builder --chown=root:root --chmod=0755 /usr/local/bin/vrg /usr/local/bin/vrg 22 | COPY --from=builder /usr/local/lib/libutils.so.*.*.* /usr/local/lib/ 23 | RUN mkdir -p /var/log/vrg && mkdir -p /var/run/vrg \ 24 | && ln -s /usr/local/lib/libutils.so.* /usr/local/lib/libutils.so \ 25 | && apt update -y && apt install -y libnuma1 libatomic1 libconfig9 iproute2\ 26 | libgrpc++1.51t64 && apt clean -y && apt autoclean -y && apt autoremove -y 27 | 28 | VOLUME /var/log/vrg 29 | VOLUME /var/run/vrg 30 | 31 | ENTRYPOINT ["/usr/local/bin/vrg"] 32 | CMD ["-l", "0-7", "-n", "4"] 33 | -------------------------------------------------------------------------------- /boot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | get_script_dir () { 6 | SOURCE="${BASH_SOURCE[0]}" 7 | while [ -h "$SOURCE" ]; do 8 | DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" 9 | SOURCE="$( readlink "$SOURCE" )" 10 | [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" 11 | done 12 | DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" 13 | echo "$DIR" 14 | } 15 | path=$(get_script_dir) 16 | pushd $path 17 | git submodule update --init --recursive 18 | popd 19 | pushd $path/lib/dpdk && meson $path/lib/dpdk_build 20 | popd 21 | pushd $path/lib/dpdk_build 22 | ninja && ninja install 23 | ldconfig 24 | popd 25 | pushd $path/lib/dpdk-kmods/linux/igb_uio 26 | make 27 | popd 28 | pushd $path/lib/libutil 29 | autoreconf --install 30 | ./configure 31 | make && make install 32 | ldconfig 33 | popd 34 | pushd $path 35 | make && make install 36 | mkdir -p /var/log/vrg 37 | mkdir -p /var/run/vrg 38 | mkdir -p /etc/vrg 39 | cp config.cfg /etc/vrg/config.cfg 40 | popd 41 | echo "✅ vRG installed successfully." 42 | -------------------------------------------------------------------------------- /src/dbg.h: -------------------------------------------------------------------------------- 1 | /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ 2 | DBG.H 3 | 4 | Designed by THE on JUN 11, 2019 5 | /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/ 6 | 7 | #ifndef _DBG_H_ 8 | #define _DBG_H_ 9 | 10 | #include 11 | 12 | #define LOGDBG 1U 13 | #define LOGINFO 2U 14 | #define LOGWARN 3U 15 | #define LOGERR 4U 16 | #define LOGUNKNOWN 0U 17 | 18 | char *PPP_state2str(U16 state); 19 | char *PPP_event2str(U16 event); 20 | char *DHCP_state2str(U16 state); 21 | 22 | /* log level, logfile fp, log msg */ 23 | #define VRG_LOG(lvl, fp, ccb, ccb2str, ...) LOGGER(LOG ## lvl, __FILE__, __LINE__, fp, ccb, ccb2str, __VA_ARGS__) 24 | 25 | void LOGGER(U8 level, char *filename, int line_num, FILE *log_fp, void *ccb, void (*ccb2str)(void *, char *), const char *fmt,...); 26 | char *loglvl2str(U8 level); 27 | U8 logstr2lvl(const char *log_str); 28 | void PPPLOGMSG(void *ccb, char *buf); 29 | void DHCPLOGMSG(void *ccb, char *buf); 30 | void dbg_init(void *ccb); 31 | 32 | #endif -------------------------------------------------------------------------------- /northbound/grpc/Makefile: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # vRG northbound makefile 3 | ############################################################ 4 | 5 | ###################################### 6 | # Set variable 7 | ###################################### 8 | CC = g++ 9 | INCLUDE = 10 | CFLAGS = $(INCLUDE) -Wall -g -O3 11 | 12 | LDFLAGS = -lutils 13 | 14 | PROTO_SRC = vrg_node.proto 15 | GRPC_SRC = $(wildcard *.cpp) 16 | PB_HDR = $(PB_SRC:.cc=.h) 17 | PB_SRC = $(PROTO_SRC:.proto=.pb.cc) $(PROTO_SRC:.proto=.grpc.pb.cc) 18 | GRPC_OBJ = $(GRPC_SRC:.cpp=.o) 19 | 20 | ###################################### 21 | # Compile & Link 22 | # Must use \tab key after new line 23 | ###################################### 24 | all: 25 | protoc --grpc_out=$(CURDIR) --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` $(PROTO_SRC) 26 | protoc --cpp_out=$(CURDIR) $(PROTO_SRC) 27 | $(CC) $(CFLAGS) -c $(GRPC_SRC) $(PB_SRC) 28 | 29 | ###################################### 30 | # Clean 31 | ###################################### 32 | clean: 33 | rm -rf $(PB_SRC) $(PB_HDR) $(GRPC_OBJ) 34 | -------------------------------------------------------------------------------- /src/pppd/nat.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include "pppd.h" 23 | 24 | extern U16 user_count; 25 | 26 | void nat_rule_timer(__attribute__((unused)) struct rte_timer *tim, PPP_INFO_t *s_ppp_ccb) 27 | { 28 | //U16 user_id; 29 | //for(user_id=0; user_idaddr_table[i].is_fill) == 1) { 32 | if (rte_atomic16_read(&s_ppp_ccb->addr_table[i].is_alive) > 0) 33 | rte_atomic16_sub(&s_ppp_ccb->addr_table[i].is_alive, 1); 34 | else 35 | rte_atomic16_set(&s_ppp_ccb->addr_table[i].is_fill, 0); 36 | } 37 | } 38 | //} 39 | } -------------------------------------------------------------------------------- /src/protocol.h: -------------------------------------------------------------------------------- 1 | #ifndef _PROTOCOL_H_ 2 | #define _PROTOCOL_H_ 3 | 4 | #include 5 | 6 | #define ETH_MTU 1500 7 | #define ETH_JUMBO 9000 8 | 9 | #define ETH_P_PPP_DIS 0x8863 10 | #define ETH_P_PPP_SES 0x8864 11 | #define VLAN 0x8100 12 | 13 | /** 14 | * @brief We use bit feild here, but bit field order is uncertain. 15 | * It depends on compiler implementation. 16 | * In GCC, bit field is bind with endianess. 17 | * https://rednaxelafx.iteye.com/blog/257760 18 | * http://www.programmer-club.com.tw/ShowSameTitleN/general/6887.html 19 | * http://pl-learning-blog.logdown.com/posts/1077056-usually-terror-words-o-muhammad-c-ch13-reading-notes-unfinished 20 | */ 21 | typedef struct vlan_header { 22 | union tci_header { 23 | U16 tci_value; 24 | struct tci_bit { 25 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 26 | U16 vlan_id:12; 27 | U16 DEI:1; 28 | U16 priority:3; 29 | #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 30 | U16 priority:3; 31 | U16 DEI:1; 32 | U16 vlan_id:12; 33 | #endif 34 | }tci_struct; 35 | }tci_union; 36 | U16 next_proto; 37 | }__rte_aligned(2) vlan_header_t; 38 | 39 | #endif -------------------------------------------------------------------------------- /northbound/grpc/vrg_grpc_server.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "vrg_node_grpc.h" 6 | #include "../../src/vrg.h" 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | void vrg_grpc_server_run(void *arg) { 13 | VRG_t *vrg_ccb = (VRG_t *)arg; 14 | 15 | std::string unix_sock_path(vrg_ccb->unix_sock_path); 16 | std::string ip_address(vrg_ccb->node_grpc_ip_port); 17 | std::cout << "grpc server starting..." << std::endl; 18 | grpc::ServerBuilder builder; 19 | 20 | grpc::EnableDefaultHealthCheckService(true); 21 | std::shared_ptr cred = grpc::InsecureServerCredentials(); 22 | builder.AddListeningPort(unix_sock_path, cred); 23 | builder.AddListeningPort(ip_address, cred); 24 | VRGNodeServiceImpl vrg_service(vrg_ccb); 25 | builder.RegisterService(&vrg_service); 26 | 27 | std::unique_ptr server(builder.BuildAndStart()); 28 | std::cout << "grpc server listening on " << unix_sock_path << std::endl; 29 | std::cout << "grpc server listening on " << ip_address << std::endl; 30 | server->Wait(); 31 | return; 32 | } 33 | 34 | #ifdef __cplusplus 35 | } 36 | #endif 37 | -------------------------------------------------------------------------------- /src/uilts.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include "utils.h" 8 | 9 | void get_all_lcore_id(struct lcore_map *lcore) 10 | { 11 | lcore->ctrl_thread = rte_get_next_lcore(rte_lcore_id(), 1, 0); 12 | lcore->wan_thread = rte_get_next_lcore(lcore->ctrl_thread, 1, 0); 13 | lcore->down_thread = rte_get_next_lcore(lcore->wan_thread, 1, 0); 14 | lcore->lan_thread = rte_get_next_lcore(lcore->down_thread, 1, 0); 15 | lcore->up_thread = rte_get_next_lcore(lcore->lan_thread, 1, 0); 16 | lcore->gateway_thread = rte_get_next_lcore(lcore->up_thread, 1, 0); 17 | lcore->timer_thread = rte_get_next_lcore(lcore->gateway_thread, 1, 0); 18 | lcore->northbound_thread = rte_get_next_lcore(lcore->timer_thread, 1, 0); 19 | } 20 | 21 | char *make_eal_args_string(int argc, const char **argv) 22 | { 23 | size_t total_len = 0; 24 | for (int i = 0; i < argc; i++) 25 | total_len += strlen(argv[i]) + 1; // '\0' 26 | 27 | char *result = (char *)malloc(total_len); 28 | if (!result) 29 | return NULL; 30 | 31 | memset(result, 0, total_len); 32 | for (int i = 0; i < argc; i++) { 33 | strcat(result, argv[i]); 34 | if (i < argc - 1) 35 | strcat(result, " "); 36 | } 37 | 38 | return result; // caller free() 39 | } 40 | -------------------------------------------------------------------------------- /unit_test/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../src/vrg.h" 4 | #include "../src/pppd/codec.h" 5 | #include "../src/dbg.h" 6 | #include "test.h" 7 | 8 | void init_ccb() 9 | { 10 | VRG_t *ccb = malloc(sizeof(VRG_t)); 11 | 12 | ccb->fp = NULL, 13 | ccb->nic_info = (struct nic_info){ 14 | .hsi_wan_src_mac = { 15 | .addr_bytes = {0x9c, 0x69, 0xb4, 0x61, 0x16, 0xdd}, 16 | }, 17 | .hsi_lan_mac = { 18 | .addr_bytes = {0x9c, 0x69, 0xb4, 0x61, 0x16, 0xdc}, 19 | }, 20 | }; 21 | ccb->loglvl = -1; 22 | codec_init((void *)ccb); 23 | dbg_init((void *)ccb); 24 | } 25 | 26 | int main() 27 | { 28 | signal(SIGCHLD, SIG_IGN); 29 | 30 | puts("====================start unit tests====================\n"); 31 | init_ccb(); 32 | puts("====================test pppd/codec.c===================="); 33 | test_build_padi(); 34 | test_build_padr(); 35 | test_build_padt(); 36 | test_build_config_request(); 37 | test_build_config_ack(); 38 | test_build_config_nak_rej(); 39 | test_build_terminate_request(); 40 | test_build_terminate_ack(); 41 | test_build_echo_reply(); 42 | test_build_auth_request_pap(); 43 | test_build_auth_ack_pap(); 44 | puts("ok!"); 45 | 46 | puts("\nall test successfully"); 47 | puts("====================end of unit tests===================="); 48 | } 49 | -------------------------------------------------------------------------------- /src/dhcpd/dhcp_fsm.h: -------------------------------------------------------------------------------- 1 | /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ 2 | dhcp_fsm.h 3 | 4 | Finite State Machine for DHCP connection/call 5 | 6 | Designed by THE on Mar 21, 2021 7 | /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/ 8 | #ifndef _DHCP_FSM_H_ 9 | #define _DHCP_FSM_H_ 10 | 11 | #include 12 | #include 13 | #include "../vrg.h" 14 | #include "dhcp_codec.h" 15 | 16 | typedef struct{ 17 | U8 state; 18 | U16 event; 19 | U8 next_state; 20 | STATUS (*hdl[10])(struct rte_timer *, dhcp_ccb_t *); 21 | } tDHCP_STATE_TBL; 22 | 23 | /*--------- STATE TYPE ----------*/ 24 | typedef enum { 25 | S_DHCP_INIT = 1, 26 | S_DHCP_DISCOVER_RECV, 27 | S_DHCP_OFFER_SENT, 28 | S_DHCP_REQUEST_RECV, 29 | S_DHCP_ACK_SENT, 30 | S_DHCP_NAK_SENT, 31 | S_DHCP_INVLD, 32 | } DHCP_STATE; 33 | 34 | /*----------------- EVENT TYPE -------------------- 35 | Q_ : Quest primitive 36 | E_ : Event */ 37 | typedef enum { 38 | E_DISCOVER = 1, 39 | E_OFFER, 40 | E_GOOD_REQUEST, 41 | E_BAD_REQUEST, 42 | E_ACK, 43 | E_NAK, 44 | E_TIMEOUT, 45 | E_RELEASE, 46 | } DHCP_EVENT_TYPE; 47 | 48 | void dhcp_fsm_init(VRG_t *ccb); 49 | 50 | /*======================= external ==========================*/ 51 | #ifdef __cplusplus 52 | extern "C" { 53 | #endif 54 | 55 | #ifdef __cplusplus 56 | } 57 | #endif 58 | 59 | #endif /* header */ -------------------------------------------------------------------------------- /unit_test/Makefile: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # vRG makefile 3 | ############################################################ 4 | 5 | ###################################### 6 | # Set variable 7 | ###################################### 8 | CC = gcc 9 | INCLUDE = 10 | CFLAGS = $(INCLUDE) -Wall -g $(shell pkg-config --cflags libdpdk) -O3 -DALLOW_EXPERIMENTAL_API 11 | 12 | LDFLAGS = $(shell pkg-config --static --libs libdpdk) -lutils -lconfig -Wl,--start-group -lstdc++ $(shell pkg-config --libs grpc++ protobuf) -lgrpc_unsecure -lgrpc++_unsecure -laddress_sorting -lpthread -Wl,--end-group 13 | 14 | TARGET = unit-tester 15 | SRC = $(wildcard *.c) $(wildcard pppd/*.c) $(wildcard dhcpd/*.c) 16 | 17 | OBJ = $(SRC:.c=.o) $(wildcard ../src/pppd/*.o) $(wildcard ../src/dhcpd/*.o) $(filter-out ../src/main.o, $(wildcard ../src/*.o)) $(filter-out ../northbound/grpc/vrg_grpc_client.o, $(wildcard ../northbound/grpc/*.o)) 18 | 19 | ifneq ($(shell pkg-config --exists libdpdk && echo 0),0) 20 | $(error "no installation of DPDK found") 21 | endif 22 | 23 | .PHONY: $(TARGET) 24 | all: $(TARGET) 25 | ###################################### 26 | # Compile & Link 27 | # Must use \tab key after new line 28 | ###################################### 29 | $(TARGET): $(OBJ) 30 | $(CC) $(CFLAGS) $(OBJ) -o $(TARGET) $(LDFLAGS) 31 | 32 | ###################################### 33 | # Clean 34 | ###################################### 35 | clean: 36 | rm -rf $(OBJ) $(TARGET) .libs 37 | -------------------------------------------------------------------------------- /northbound/cmdline/Makefile: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # vRG makefile 3 | ############################################################ 4 | 5 | ###################################### 6 | # Set variable 7 | ###################################### 8 | CC = gcc 9 | INCLUDE = -I../../src -I../grpc 10 | CFLAGS = $(INCLUDE) -Wall -g $(shell pkg-config --cflags libdpdk) -O3 -DALLOW_EXPERIMENTAL_API -D_TEST_MODE #-Wextra -fsanitize=address 11 | 12 | LDFLAGS = $(shell pkg-config --static --libs libdpdk) -lutils -lconfig -Wl,--start-group -lstdc++ -lgrpc -lgrpc++ -lgrpc_unsecure -lgrpc++_unsecure -lgpr -laddress_sorting -pthread -lprotobuf -lpthread -Wl,--end-group 13 | 14 | TARGET = vrg_cli 15 | SRC = $(wildcard *.c) 16 | OBJ = $(SRC:.c=.o) 17 | 18 | GRPCDIR = ../grpc 19 | GRPC_SRC = $(GRPCDIR)/vrg_grpc_client.cpp 20 | PB_SRC = $(wildcard $(GRPCDIR)/*.cc) 21 | GRPC_OBJ = $(GRPC_SRC:.cpp=.o) 22 | PB_OBJ = $(PB_SRC:.cc=.o) 23 | 24 | ifneq ($(shell pkg-config --exists libdpdk && echo 0),0) 25 | $(error "no installation of DPDK found") 26 | endif 27 | 28 | .PHONY: $(TARGET) 29 | all: $(TARGET) 30 | ###################################### 31 | # Compile & Link 32 | # Must use \tab key after new line 33 | ###################################### 34 | $(TARGET): $(OBJ) $(GRPC_OBJ) $(PB_OBJ) 35 | $(CC) $(CFLAGS) $(OBJ) $(GRPC_OBJ) $(PB_OBJ) -o $(TARGET) $(LDFLAGS) 36 | 37 | ###################################### 38 | # Clean 39 | ###################################### 40 | clean: 41 | rm -rf $(OBJ) $(TARGET) .libs 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2019, THE 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /src/ethtool.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int rte_ethtool_get_drvinfo(U16 port_id, struct ethtool_drvinfo *drvinfo) 10 | { 11 | struct rte_eth_dev_info dev_info; 12 | struct rte_dev_reg_info reg_info; 13 | int n; 14 | 15 | if (drvinfo == NULL) 16 | return -EINVAL; 17 | 18 | RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV); 19 | 20 | int ret = rte_eth_dev_fw_version_get(port_id, drvinfo->fw_version, 21 | sizeof(drvinfo->fw_version)); 22 | if (ret < 0) 23 | printf("firmware version get error: (%s)\n", strerror(-ret)); 24 | else if (ret > 0) 25 | printf("Insufficient fw version buffer size, " 26 | "the minimum size should be %d\n", ret); 27 | 28 | memset(&dev_info, 0, sizeof(dev_info)); 29 | rte_eth_dev_info_get(port_id, &dev_info); 30 | 31 | strlcpy(drvinfo->driver, dev_info.driver_name, sizeof(drvinfo->driver)); 32 | strlcpy(drvinfo->version, rte_version(), sizeof(drvinfo->version)); 33 | strlcpy(drvinfo->bus_info, rte_dev_name(dev_info.device), sizeof(drvinfo->bus_info)); 34 | 35 | memset(®_info, 0, sizeof(reg_info)); 36 | rte_eth_dev_get_reg_info(port_id, ®_info); 37 | n = reg_info.length; 38 | if (n > 0) 39 | drvinfo->regdump_len = n; 40 | else 41 | drvinfo->regdump_len = 0; 42 | 43 | n = rte_eth_dev_get_eeprom_length(port_id); 44 | if (n > 0) 45 | drvinfo->eedump_len = n; 46 | else 47 | drvinfo->eedump_len = 0; 48 | 49 | drvinfo->n_stats = sizeof(struct rte_eth_stats) / sizeof(uint64_t); 50 | drvinfo->testinfo_len = 0; 51 | 52 | return 0; 53 | } -------------------------------------------------------------------------------- /northbound/grpc/vrg_node_grpc.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "vrg_node.grpc.pb.h" 3 | #include "../../src/vrg.h" 4 | 5 | using namespace std; 6 | using namespace vrgnodeservice; 7 | 8 | class VRGNodeServiceImpl final : public vrgnodeservice::VrgService::Service 9 | { 10 | public: 11 | explicit VRGNodeServiceImpl(VRG_t* ctx) : vrg_ccb(ctx) {} 12 | 13 | ::grpc::Status ConnectHsi(::grpc::ServerContext* context, const ::vrgnodeservice::HsiRequest* request, ::vrgnodeservice::HsiReply* response) override; 14 | ::grpc::Status DisconnectHsi(::grpc::ServerContext* context, const ::vrgnodeservice::HsiRequest* request, ::vrgnodeservice::HsiReply* response) override; 15 | ::grpc::Status DhcpServerStart(::grpc::ServerContext* context, const ::vrgnodeservice::DhcpServerRequest* request, ::vrgnodeservice::DhcpServerReply* response) override; 16 | ::grpc::Status DhcpServerStop(::grpc::ServerContext* context, const ::vrgnodeservice::DhcpServerRequest* request, ::vrgnodeservice::DhcpServerReply* response) override; 17 | ::grpc::Status GetVrgSystemInfo(::grpc::ServerContext* context, const ::google::protobuf::Empty* request, ::vrgnodeservice::VrgSystemInfo* response) override; 18 | ::grpc::Status GetVrgHsiInfo(::grpc::ServerContext* context, const ::google::protobuf::Empty* request, ::vrgnodeservice::VrgHsiInfo* response) override; 19 | ::grpc::Status GetVrgDhcpInfo(::grpc::ServerContext* context, const ::google::protobuf::Empty* request, ::vrgnodeservice::VrgDhcpInfo* response) override; 20 | ::grpc::Status GetNodeStatus(::grpc::ServerContext* context, const ::google::protobuf::Empty* request, ::vrgnodeservice::NodeStatus* response) override; 21 | 22 | private: 23 | VRG_t* vrg_ccb; 24 | }; -------------------------------------------------------------------------------- /essensials.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | # Detect OS (Ubuntu / RHEL / CentOS / Rocky / AlmaLinux) 5 | if [ -f /etc/os-release ]; then 6 | . /etc/os-release 7 | OS_ID=$ID 8 | OS_VERSION_ID=$VERSION_ID 9 | else 10 | echo "❌ Cannot detect OS" 11 | exit 1 12 | fi 13 | 14 | echo "Detected OS: $OS_ID $OS_VERSION_ID" 15 | 16 | if [[ "$OS_ID" =~ (rhel|centos|rocky|almalinux) ]]; then 17 | echo "➡ Installing dependencies for RHEL/CentOS family" 18 | 19 | # Extract major version (e.g. 8, 9) 20 | OS_MAJOR=$(echo "$OS_VERSION_ID" | cut -d. -f1) 21 | 22 | # Install EPEL (automatically match major version) 23 | EPEL_URL="https://dl.fedoraproject.org/pub/epel/epel-release-latest-${OS_MAJOR}.noarch.rpm" 24 | echo "Downloading EPEL from: $EPEL_URL" 25 | wget -q "$EPEL_URL" -O /tmp/epel-release.rpm 26 | rpm -Uvh /tmp/epel-release.rpm 27 | 28 | # Install packages 29 | dnf -y --enablerepo=crb install protobuf-devel || true 30 | dnf -y --enablerepo=devel install meson libconfig-devel protobuf-compiler || true 31 | dnf -y install grpc grpc-cpp grpc-devel 32 | dnf -y install python3-pyelftools 33 | 34 | elif [[ "$OS_ID" == "ubuntu" ]]; then 35 | echo "➡ Installing dependencies for Ubuntu (tested on 24.04)" 36 | 37 | apt-get update -y 38 | apt-get install -y \ 39 | libnuma-dev \ 40 | linux-headers-$(uname -r) \ 41 | git gcc make libtool-bin pkg-config pciutils iproute2 \ 42 | kmod vim net-tools libconfig-dev \ 43 | libgrpc++-dev protobuf-compiler-grpc libabsl-dev meson \ 44 | python3-pyelftools ninja-build python3-setuptools 45 | 46 | apt-get clean -y 47 | apt-get autoclean -y 48 | apt-get autoremove -y 49 | 50 | else 51 | echo "❌ Unsupported OS: $OS_ID" 52 | exit 1 53 | fi 54 | 55 | echo "✅ Dependencies installed successfully." 56 | -------------------------------------------------------------------------------- /src/pppd/codec.h: -------------------------------------------------------------------------------- 1 | /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ 2 | PPP_CODEC.H 3 | 4 | Designed by THE on Jan 14, 2019 5 | /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/ 6 | 7 | #ifndef _CODEC_H_ 8 | #define _CODEC_H_ 9 | 10 | #include 11 | #include 12 | #include 13 | #include "../vrg.h" 14 | #include "header.h" 15 | #include "pppd.h" 16 | #include "fsm.h" 17 | 18 | void codec_init(void *ccb); 19 | 20 | STATUS PPP_decode_frame(tVRG_MBX *mail, U16 *event, PPP_INFO_t *s_ppp_ccb); 21 | 22 | void build_config_request(U8 *buffer, U16 *mulen, PPP_INFO_t *s_ppp_ccb); 23 | void build_config_ack(U8 *buffer, U16 *mulen, PPP_INFO_t *s_ppp_ccb); 24 | void build_config_nak_rej(U8 *buffer, U16 *mulen, PPP_INFO_t *s_ppp_ccb); 25 | void build_terminate_ack(U8 *buffer, U16 *mulen, PPP_INFO_t *s_ppp_ccb); 26 | extern STATUS build_code_reject(U8 *buffer, PPP_INFO_t *s_ppp_ccb, U16 *mulen); 27 | void build_terminate_request(U8 *buffer, U16 *mulen, PPP_INFO_t *s_ppp_ccb); 28 | void build_echo_reply(U8 *buffer, U16 *mulen, PPP_INFO_t *s_ppp_ccb); 29 | void build_auth_request_pap(U8 *buffer, U16 *mulen, PPP_INFO_t *s_ppp_ccb); 30 | void build_auth_ack_pap(U8 *buffer, U16 *mulen, PPP_INFO_t *s_ppp_ccb); 31 | void build_auth_response_chap(U8 *buffer, U16 *mulen, PPP_INFO_t *s_ppp_ccb, ppp_chap_data_t *ppp_chap_data); 32 | 33 | STATUS build_padi(U8 *buffer, U16 *mulen, PPP_INFO_t *s_ppp_ccb); 34 | STATUS build_padr(U8 *buffer, U16 *mulen, PPP_INFO_t *s_ppp_ccb); 35 | void build_padt(U8 *buffer, U16 *mulen, PPP_INFO_t *s_ppp_ccb); 36 | STATUS send_pkt(U8 encode_type, PPP_INFO_t *s_ppp_ccb); 37 | 38 | STATUS get_session_id(tVRG_MBX *vrg_mail, U16 *session_index); 39 | int check_auth_result(PPP_INFO_t *s_ppp_ccb); 40 | 41 | typedef enum { 42 | ENCODE_PADI, 43 | ENCODE_PADR, 44 | ENCODE_PADT, 45 | }PPP_CODE_TYPE_t; 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /src/pppd/fsm.h: -------------------------------------------------------------------------------- 1 | /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ 2 | fsm.h 3 | 4 | Finite State Machine for PPP connection/call 5 | 6 | Designed by THE on Jan 14, 2019 7 | /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/ 8 | #include 9 | #include "codec.h" 10 | 11 | #ifndef _FSM_H_ 12 | #define _FSM_H_ 13 | 14 | typedef struct{ 15 | U8 state; 16 | U16 event; 17 | U8 next_state; 18 | STATUS (*hdl[10])(struct rte_timer *, PPP_INFO_t *); 19 | } tPPP_STATE_TBL; 20 | 21 | /*--------- STATE TYPE ----------*/ 22 | typedef enum { 23 | S_INIT, 24 | S_STARTING, 25 | S_CLOSED, 26 | S_STOPPED, 27 | S_CLOSING, 28 | S_STOPPING, 29 | S_REQUEST_SENT, 30 | S_ACK_RECEIVED, 31 | S_ACK_SENT, 32 | S_OPENED, 33 | S_INVLD, 34 | } PPP_STATE; 35 | 36 | /*----------------- EVENT TYPE -------------------- 37 | Q_ : Quest primitive 38 | E_ : Event */ 39 | typedef enum { 40 | E_UP, 41 | E_DOWN, 42 | E_OPEN, 43 | E_CLOSE, 44 | E_TIMEOUT_COUNTER_POSITIVE, 45 | E_TIMEOUT_COUNTER_EXPIRED, 46 | E_RECV_GOOD_CONFIG_REQUEST, 47 | E_RECV_BAD_CONFIG_REQUEST, 48 | E_RECV_CONFIG_ACK, 49 | E_RECV_CONFIG_NAK_REJ, 50 | E_RECV_TERMINATE_REQUEST, 51 | E_RECV_TERMINATE_ACK, 52 | E_RECV_UNKNOWN_CODE, 53 | E_RECV_GOOD_CODE_PROTOCOL_REJECT, 54 | E_RECV_BAD_CODE_PROTOCOL_REJECT, 55 | E_RECV_ECHO_REPLY_REQUEST_DISCARD_REQUEST, 56 | E_UNKNOWN, // for log usage, not for fsm 57 | } PPP_EVENT_TYPE; 58 | 59 | STATUS A_padi_timer_func(__attribute__((unused)) struct rte_timer *tim, __attribute__((unused)) PPP_INFO_t *s_ppp_ccb); 60 | STATUS A_padr_timer_func(__attribute__((unused)) struct rte_timer *tim, __attribute__((unused)) PPP_INFO_t *s_ppp_ccb); 61 | void fsm_init(void *ccb); 62 | 63 | /*======================= external ==========================*/ 64 | #ifdef __cplusplus 65 | extern "C" { 66 | #endif 67 | 68 | #ifdef __cplusplus 69 | } 70 | #endif 71 | 72 | #endif /* header */ 73 | -------------------------------------------------------------------------------- /src/dp_flow.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "pppd/pppd.h" 4 | #include "vrg.h" 5 | 6 | #define MAX_PATTERN_NUM 4 7 | 8 | struct rte_flow *generate_flow(U16 port_id, U16 rx_q, struct rte_flow_error *error); 9 | 10 | struct rte_flow *generate_flow(U16 port_id, U16 rx_q, struct rte_flow_error *error) 11 | { 12 | struct rte_flow_attr attr; 13 | struct rte_flow_item pattern[MAX_PATTERN_NUM]; 14 | struct rte_flow_action action[MAX_PATTERN_NUM]; 15 | struct rte_flow *flow = NULL; 16 | struct rte_flow_action_queue queue = { .index = rx_q }; 17 | struct rte_flow_item_eth eth_spec, eth_mask; 18 | struct rte_flow_item_vlan vlan_spec, vlan_mask; 19 | int res; 20 | 21 | memset(pattern,0,sizeof(pattern)); 22 | memset(action,0,sizeof(action)); 23 | 24 | /* 25 | * set the rule attribute. 26 | * in this case only ingress packets will be checked. 27 | */ 28 | memset(&attr,0,sizeof(struct rte_flow_attr)); 29 | attr.ingress = 1; 30 | 31 | /* 32 | * create the action sequence. 33 | * one action only, move packet to queue 34 | */ 35 | 36 | action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE; 37 | action[0].conf = &queue; 38 | action[1].type = RTE_FLOW_ACTION_TYPE_END; 39 | 40 | /* 41 | * set the first level of the pattern (eth). 42 | * since in this example we just want to get the 43 | * ipv4 we set this level to allow all. 44 | */ 45 | memset(ð_spec, 0, sizeof(struct rte_flow_item_eth)); 46 | memset(ð_mask, 0, sizeof(struct rte_flow_item_eth)); 47 | //rte_ether_addr_copy(&(vrg_ccb.hsi_lan_mac), ð_spec.dst); 48 | for(int i=0; i $@ 42 | @echo "#define VERSION_H" >> $@ 43 | @echo "" >> $@ 44 | @echo "#define GIT_COMMIT_ID \"$(GIT_COMMIT)\"" >> $@ 45 | @echo "#define BUILD_TIME \"$(BUILD_TIME)\"" >> $@ 46 | @echo "" >> $@ 47 | @echo "#endif" >> $@ 48 | 49 | $(TARGET): $(VERSION_H) $(OBJ) 50 | ${MAKE} -C $(GRPCDIR) 51 | $(CC) $(CFLAGS) $(OBJ) $(GRPC_OBJ) -o $(TARGET) $(LDFLAGS) 52 | 53 | install: 54 | cp $(TARGET) /usr/local/bin/$(TARGET) 55 | 56 | test: $(TARGET) 57 | ${MAKE} -C $(TESTDIR) 58 | ulimit -s 16384 && ./$(TESTDIR)/$(TESTBIN) 59 | 60 | ###################################### 61 | # Clean 62 | ###################################### 63 | clean: 64 | rm -rf $(OBJ) $(TARGET) .libs $(VERSION_H) 65 | $(MAKE) -C $(TESTDIR) -f Makefile $@ 66 | $(MAKE) -C $(GRPCDIR) -f Makefile $@ 67 | 68 | uninstall: 69 | rm -f /usr/local/bin/$(TARGET) 70 | -------------------------------------------------------------------------------- /src/dhcpd/dhcp_codec.h: -------------------------------------------------------------------------------- 1 | /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ 2 | DHCP_CODEC.H 3 | 4 | Designed by THE on MAR 21, 2021 5 | /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/ 6 | 7 | #ifndef _DHCP_CODEC_H_ 8 | #define _DHCP_CODEC_H_ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "../protocol.h" 15 | 16 | #define MAX_IP_POOL 100 17 | #define LAN_USER MAX_IP_POOL 18 | #define LEASE_TIMEOUT 3600 19 | 20 | typedef struct dhcp_info dhcp_info_t; 21 | 22 | typedef struct ip_pool { 23 | struct rte_ether_addr mac_addr; 24 | U32 ip_addr; 25 | BOOL used; 26 | }ip_pool_t; 27 | 28 | typedef struct lan_user_info { 29 | U8 state; 30 | U32 timer_counter; 31 | BOOL lan_user_used; 32 | struct rte_ether_addr mac_addr; 33 | struct rte_timer timer; 34 | struct rte_timer lan_user_timer; 35 | }lan_user_info_t; 36 | 37 | typedef struct dhcp_ccb { 38 | dhcp_info_t *dhcp_info; 39 | struct rte_ether_hdr *eth_hdr; 40 | vlan_header_t *vlan_hdr; 41 | struct rte_ipv4_hdr *ip_hdr; 42 | struct rte_udp_hdr *udp_hdr; 43 | U32 dhcp_server_ip; 44 | U8 cur_lan_user_index; 45 | U8 cur_ip_pool_index; 46 | ip_pool_t ip_pool[MAX_IP_POOL]; 47 | lan_user_info_t lan_user_info[LAN_USER]; 48 | rte_atomic16_t dhcp_bool; //boolean value for accept dhcp packets at data plane 49 | }dhcp_ccb_t; 50 | 51 | BIT16 dhcp_decode(dhcp_ccb_t *dhcp_ccb, struct rte_ether_hdr *eth_hdr, vlan_header_t *vlan_header, struct rte_ipv4_hdr *ip_hdr, struct rte_udp_hdr *udp_hdr); 52 | 53 | #define DHCP_SUBNET_MASK 1 54 | #define DHCP_ROUTER 3 55 | #define DHCP_DNS 6 56 | #define DHCP_HOSTNAME 12 57 | #define DHCP_REQUEST_IP 50 58 | #define DHCP_LEASE_TIME 51 59 | #define DHCP_MSG_TYPE 53 60 | #define DHCP_SERVER_ID 54 61 | #define DHCP_PARAMETER_LIST 55 62 | #define DHCP_RENEWAL_VAL 58 63 | #define DHCP_REBIND_TIME_VAL 59 64 | #define DHCP_ISP_ID 60 65 | #define DHCP_CLIENT_ID 61 66 | #define DHCP_END 255 67 | 68 | enum { 69 | DHCP_DISCOVER = 1, 70 | DHCP_OFFER, 71 | DHCP_REQUEST, 72 | DHCP_DECLINE, 73 | DHCP_ACK, 74 | DHCP_NAK, 75 | DHCP_RELEASE, 76 | DHCP_INFORM, 77 | DHCP_FORCE_RENEW, 78 | DHCP_LEASE_QUERY, 79 | DHCP_LEASE_UNASSIGNED, 80 | DHCP_LEASE_UNKNOWN, 81 | DHCP_LEASE_ACTIVE, 82 | }; 83 | 84 | #endif -------------------------------------------------------------------------------- /src/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef _UTILS_H_ 2 | #define _UTILS_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "protocol.h" 8 | 9 | #define RING_BURST_SIZE 32 10 | 11 | /** 12 | * @brief msg between IF driver and daemon 13 | */ 14 | typedef struct { 15 | U16 type; 16 | U8 refp[ETH_JUMBO]; 17 | int len; 18 | } tVRG_MBX; 19 | 20 | /* only execution when condition is true */ 21 | #define VRG_ASSERT(cond, op, ret) do { \ 22 | if (unlikely(!(cond))) { \ 23 | (ret) = (op); \ 24 | } \ 25 | } while(0) 26 | 27 | static inline void *_vrg_malloc(size_t size, unsigned int aligned) { 28 | if (unlikely(size == 0)) { 29 | return NULL; 30 | } 31 | return rte_malloc(NULL, size, aligned); 32 | } 33 | 34 | static inline void vrg_mfree(void *ptr) { 35 | if (unlikely(ptr == NULL)) { 36 | return; 37 | } 38 | rte_free(ptr); 39 | } 40 | 41 | #define vrg_malloc(type, size, aligned) (type *)_vrg_malloc(size, aligned) 42 | 43 | /** 44 | * vrg_ring_enqueue 45 | * 46 | * @brief 47 | * vrg lockless ring enqueue, it will try to enqueue all mails 48 | * @param ring 49 | * ring pointer 50 | * @param mails 51 | * mail array 52 | * @param enqueue_num 53 | * mail amount 54 | * @return 55 | * void 56 | */ 57 | static inline void vrg_ring_enqueue(struct rte_ring *ring, void **mails, unsigned int enqueue_num) 58 | { 59 | unsigned int burst_size = 0; 60 | unsigned int rest_num = enqueue_num; 61 | 62 | for(;;) { 63 | int rest_mails_index = enqueue_num - rest_num; 64 | burst_size = rte_ring_enqueue_burst(ring, &mails[rest_mails_index], rest_num, NULL); 65 | rest_num -= burst_size; 66 | if (likely(rest_num == 0)) 67 | break; 68 | } 69 | return; 70 | } 71 | 72 | /** 73 | * vrg_ring_dequeue 74 | * 75 | * @brief 76 | * vrg lockless ring dequeue, it will return once there is a mail 77 | * @param ring 78 | * ring pointer 79 | * @param mails 80 | * mail array 81 | * @return 82 | * mail amount 83 | */ 84 | static inline int vrg_ring_dequeue(struct rte_ring *ring, void **mail) 85 | { 86 | U16 burst_size; 87 | 88 | for(;;) { 89 | burst_size = rte_ring_dequeue_burst(ring, mail, RING_BURST_SIZE, NULL); 90 | if (likely(burst_size == 0)) 91 | continue; 92 | break; 93 | } 94 | return burst_size; 95 | } 96 | 97 | struct lcore_map { 98 | U8 ctrl_thread; 99 | U8 wan_thread; 100 | U8 down_thread; 101 | U8 lan_thread; 102 | U8 up_thread; 103 | U8 gateway_thread; 104 | U8 timer_thread; 105 | U8 northbound_thread; 106 | }; 107 | 108 | void get_all_lcore_id(struct lcore_map *lcore); 109 | char *make_eal_args_string(int argc, const char **argv); 110 | 111 | #endif -------------------------------------------------------------------------------- /src/vrg.h: -------------------------------------------------------------------------------- 1 | #ifndef _VRG_H_ 2 | #define _VRG_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "dhcpd/dhcp_codec.h" 13 | #include "protocol.h" 14 | #include "pppd/pppd.h" 15 | #include "utils.h" 16 | 17 | #define LINK_DOWN 0x0 18 | #define LINK_UP 0x1 19 | 20 | enum { 21 | CLI_QUIT = 0, 22 | CLI_DISCONNECT, 23 | CLI_CONNECT, 24 | CLI_DHCP_START, 25 | CLI_DHCP_STOP, 26 | }; 27 | 28 | #define VRG_SUBMODULE_IS_ENABLED 1 << 0 29 | #define VRG_SUBMODULE_IS_DISABLED 1 << 1 30 | #define VRG_SUBMODULE_IS_FORCE_DISABLED 1 << 2 31 | #define VRG_SUBMODULE_IS_SPAWNING 1 << 3 32 | #define VRG_SUBMODULE_IS_TERMINATING 1 << 4 33 | #define VRG_SUBMODULE_IS_SPAWNED 1 << 5 34 | #define VRG_SUBMODULE_IS_TERMINATED 1 << 6 35 | 36 | typedef struct { 37 | U8 is_hsi_enable; /* hsi switch from northbound */ 38 | U8 is_dhcp_server_enable; /* dhcp server switch from northbound */ 39 | }vrg_feature_switch_t; 40 | 41 | struct nic_info { 42 | char vendor_name[16]; 43 | U16 vendor_id; 44 | struct rte_ether_addr hsi_wan_src_mac;/* vRG WAN side mac addr */ 45 | struct rte_ether_addr hsi_lan_mac; /* vRG LAN side mac addr */ 46 | }; 47 | 48 | /* vRG system data structure */ 49 | typedef struct { 50 | U8 cur_user; /* pppoe alive user count */ 51 | U8 loglvl; /* vRG loglvl */ 52 | char *version; /* vRG version */ 53 | char *build_date; /* build date */ 54 | char *eal_args; /* DPDK EAL args */ 55 | BOOL non_vlan_mode; /* non vlan or vlan mode */ 56 | U16 user_count; /* total vRG subscriptor */ 57 | U16 base_vlan; /* started vlan id */ 58 | volatile BOOL quit_flag; /* vRG quit flag */ 59 | U32 lan_ip; /* vRG LAN side ip */ 60 | struct lcore_map lcore; /* lcore map */ 61 | char *unix_sock_path;/* vRG unix socket file path */ 62 | char *node_grpc_ip_port; /* vRG node grpc ip:port */ 63 | int unix_sock_fd; /* vRG unix socket file descriptor */ 64 | FILE *fp; /* vRG log file pointer */ 65 | struct cmdline *cl; 66 | struct nic_info nic_info; 67 | PPP_INFO_t *ppp_ccb; /* pppoe control block */ 68 | dhcp_ccb_t *dhcp_ccb; /* dhcp control block */ 69 | vrg_feature_switch_t *vrg_switch; 70 | struct rte_timer link; /* for physical link checking timer */ 71 | }__rte_cache_aligned VRG_t; 72 | 73 | int vrg_start(int argc, char **argv); 74 | void vrg_interrupt(); 75 | 76 | #ifdef __cplusplus 77 | } 78 | #endif 79 | 80 | #endif -------------------------------------------------------------------------------- /src/config.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "vrg.h" 4 | #include "dbg.h" 5 | #include "config.h" 6 | 7 | STATUS parse_config(const char *config_path, VRG_t *vrg_ccb, struct vrg_config *vrg_cfg) 8 | { 9 | config_t cfg; 10 | int user_count, base_vlan, non_vlan_mode; 11 | const char *loglvl, *default_gateway, *unix_sock_path, *log_path, *node_grpc_port; 12 | 13 | config_init(&cfg); 14 | if (!config_read_file(&cfg, config_path)) { 15 | fprintf(stderr, "read config file %s content error: %s:%d - %s\n", 16 | config_path, config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg)); 17 | config_destroy(&cfg); 18 | return ERROR; 19 | } 20 | if (config_lookup_int(&cfg, "UserCount", &user_count) == CONFIG_FALSE) 21 | user_count = 1; 22 | vrg_ccb->user_count = user_count; 23 | if (config_lookup_int(&cfg, "BaseVlan", &base_vlan) == CONFIG_FALSE) 24 | base_vlan = 2; 25 | vrg_ccb->base_vlan = base_vlan; 26 | if (config_lookup_string(&cfg, "Loglvl", &loglvl) == CONFIG_FALSE) 27 | loglvl = "DBG"; 28 | vrg_ccb->loglvl = logstr2lvl(loglvl); 29 | if (vrg_ccb->loglvl == 0) { 30 | fprintf(stderr, "log level error\n"); 31 | config_destroy(&cfg); 32 | return ERROR; 33 | } 34 | if (config_lookup_string(&cfg, "LogPath", &log_path) == CONFIG_FALSE) { 35 | log_path = "/var/log/vrg/vrg.log"; 36 | printf("log path not found, use default path: %s\n", log_path); 37 | } 38 | strncpy(vrg_cfg->log_path, log_path, sizeof(vrg_cfg->log_path) - 1); 39 | vrg_cfg->log_path[sizeof(vrg_cfg->log_path) - 1] = '\0'; 40 | 41 | if (config_lookup_int(&cfg, "NonVlanMode", &non_vlan_mode) == CONFIG_FALSE) 42 | non_vlan_mode = 0; 43 | vrg_ccb->non_vlan_mode = non_vlan_mode; 44 | 45 | if (config_lookup_string(&cfg, "DefaultGateway", &default_gateway) == CONFIG_FALSE) 46 | default_gateway = "192.168.2.1"; 47 | vrg_ccb->lan_ip = inet_addr(default_gateway); 48 | 49 | if (config_lookup_string(&cfg, "NodeGrpcUnixSocket", &unix_sock_path) == CONFIG_FALSE) 50 | unix_sock_path = "unix:///var/run/vrg/vrg.sock"; 51 | strncpy(vrg_cfg->unix_sock_path, unix_sock_path, sizeof(vrg_cfg->unix_sock_path) - 1); 52 | vrg_cfg->unix_sock_path[sizeof(vrg_cfg->unix_sock_path) - 1] = '\0'; 53 | 54 | if (config_lookup_string(&cfg, "NodeGrpcPort", &node_grpc_port) == CONFIG_FALSE) 55 | node_grpc_port = "50051"; 56 | char node_grpc_ip_port[64]; // "0.0.0.0:PORT" 57 | snprintf(node_grpc_ip_port, sizeof(node_grpc_ip_port), "0.0.0.0:%s", node_grpc_port); 58 | strncpy(vrg_cfg->node_grpc_ip_port, node_grpc_ip_port, sizeof(vrg_cfg->node_grpc_ip_port) - 1); 59 | vrg_cfg->node_grpc_ip_port[sizeof(vrg_cfg->node_grpc_ip_port) - 1] = '\0'; 60 | 61 | config_destroy(&cfg); 62 | 63 | return SUCCESS; 64 | } -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*" 7 | 8 | permissions: 9 | contents: write 10 | 11 | jobs: 12 | release: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v5 18 | with: 19 | fetch-depth: 0 20 | 21 | - name: Generate release body 22 | id: release_body 23 | shell: bash 24 | run: | 25 | set -euo pipefail 26 | 27 | git fetch --tags --force 28 | 29 | current_tag="${GITHUB_REF_NAME}" 30 | 31 | prev_tag="$(git tag --sort=-creatordate | grep -vx "$current_tag" | head -n 1 || true)" 32 | 33 | if [ -n "${prev_tag:-}" ]; then 34 | range="${prev_tag}..${current_tag}" 35 | header="New commits: ${prev_tag}..${current_tag}" 36 | else 37 | range="${current_tag}" 38 | header="New commits: first time to ${current_tag}" 39 | fi 40 | 41 | repo_url="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}" 42 | 43 | tmp="$(mktemp)" 44 | git log --no-merges --pretty=format:'%s|%h|%H' ${range} > "$tmp" || true 45 | 46 | map_section_title() { 47 | case "$1" in 48 | feat) echo "feature: " ;; 49 | fix) echo "fix bug: " ;; 50 | docs) echo "documents: " ;; 51 | style) echo "style: " ;; 52 | refactor) echo "refactor: " ;; 53 | perf) echo "performance: " ;; 54 | test) echo "test: " ;; 55 | chore) echo "chore: " ;; 56 | revert) echo "revert: " ;; 57 | esac 58 | } 59 | 60 | body_file="$(mktemp)" 61 | echo "# Release ${current_tag}" >> "$body_file" 62 | echo "" >> "$body_file" 63 | echo "${header}" >> "$body_file" 64 | echo "" >> "$body_file" 65 | 66 | types=(feat fix docs style refactor perf test chore revert) 67 | total_count=0 68 | 69 | for t in "${types[@]}"; do 70 | entries="$(awk -F'|' -v t="^${t}([^)]+)?: " -v repo_url="$repo_url" ' 71 | $1 ~ t { 72 | # $1=subject, $2=short, $3=full 73 | printf("- %s ([%s](%s/commit/%s))\n", $1, $2, repo_url, $3) 74 | }' "$tmp")" 75 | 76 | if [ -n "$entries" ]; then 77 | total_count=$((total_count+1)) 78 | echo "## $(map_section_title "$t")" >> "$body_file" 79 | echo "$entries" >> "$body_file" 80 | echo "" >> "$body_file" 81 | fi 82 | done 83 | 84 | { 85 | echo "body<> "$GITHUB_OUTPUT" 89 | 90 | - name: Create GitHub Release 91 | uses: softprops/action-gh-release@v2 92 | with: 93 | tag_name: ${{ github.ref_name }} 94 | name: Release ${{ github.ref_name }} 95 | body: ${{ steps.release_body.outputs.body }} 96 | env: 97 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 98 | -------------------------------------------------------------------------------- /src/pppd/pppd.h: -------------------------------------------------------------------------------- 1 | /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ 2 | PPPD.H 3 | 4 | For ppp detection 5 | 6 | Designed by THE on Jan 14, 2019 7 | /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/ 8 | 9 | #ifndef _PPPD_H_ 10 | #define _PPPD_H_ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "header.h" 17 | 18 | #define PPP_MSG_BUF_LEN 128 19 | 20 | #define MULTICAST_TAG 4001 21 | #define TOTAL_SOCK_PORT 65536 22 | 23 | /** 24 | * @brief hsi nat table structure 25 | */ 26 | typedef struct addr_table { 27 | struct rte_ether_addr mac_addr; 28 | U32 src_ip; 29 | U32 dst_ip; 30 | U16 port_id; 31 | rte_atomic16_t is_fill; 32 | rte_atomic16_t is_alive; 33 | }__rte_cache_aligned addr_table_t; 34 | 35 | /** 36 | * @brief hsi control block structure 37 | */ 38 | typedef struct { 39 | U16 user_num; /* subscriptor id */ 40 | U16 vlan; /* subscriptor vlan */ 41 | struct rte_ether_hdr eth_hdr; 42 | vlan_header_t vlan_header __rte_aligned(sizeof(vlan_header_t)); 43 | pppoe_header_t pppoe_header __rte_aligned(sizeof(vlan_header_t)); 44 | ppp_phase_t ppp_phase[2]; /* store lcp and ipcp info, index 0 means lcp, index 1 means ipcp */ 45 | pppoe_phase_t pppoe_phase; /* store pppoe info */ 46 | U8 cp:1; /* cp is "control protocol", means we need to determine cp is LCP or NCP after parsing packet */ 47 | U8 phase:7; /* pppoe connection phase */ 48 | U16 session_id; /* pppoe session id */ 49 | struct rte_ether_addr PPP_dst_mac; /* pppoe server mac addr */ 50 | U32 hsi_ipv4; /* ip addr pppoe server assign to pppoe client */ 51 | U32 hsi_ipv4_gw; /* ip addr gateway pppoe server assign to pppoe client */ 52 | U32 hsi_primary_dns;/* 1st dns addr pppoe server assign to pppoe client */ 53 | U32 hsi_second_dns; /* 2nd dns addr pppoe server assign to pppoe client */ 54 | U8 identifier; /* ppp pkt id */ 55 | U32 magic_num; /* ppp pkt magic number, in network order */ 56 | BOOL is_pap_auth; /* pap auth boolean flag */ 57 | U16 auth_method; /* use chap or pap */ 58 | U8 *ppp_user_id; /* pap/chap account */ 59 | U8 *ppp_passwd; /* pap/chap password */ 60 | rte_atomic16_t ppp_bool; /* boolean flag for accept ppp packets at data plane */ 61 | rte_atomic16_t dp_start_bool; /* hsi data plane starting boolean flag */ 62 | BOOL ppp_processing; /* boolean flag for checking ppp is disconnecting */ 63 | addr_table_t addr_table[TOTAL_SOCK_PORT]; /* hsi nat addr table */ 64 | struct rte_timer pppoe; /* pppoe timer */ 65 | struct rte_timer ppp; /* ppp timer */ 66 | struct rte_timer nat; /* nat table timer */ 67 | struct rte_timer ppp_alive; /* PPP connection checking timer */ 68 | }__rte_cache_aligned PPP_INFO_t; 69 | 70 | extern U32 ppp_interval; 71 | 72 | void exit_ppp(__attribute__((unused)) struct rte_timer *tim, PPP_INFO_t *ppp_ccb); 73 | STATUS ppp_process(void *mail); 74 | STATUS ppp_connect(PPP_INFO_t *ppp_ccb, U16 user_id); 75 | STATUS ppp_disconnect(PPP_INFO_t *ppp_ccb, U16 user_id); 76 | STATUS pppd_init(void *ccb); 77 | void PPP_bye(PPP_INFO_t *ppp_ccb); 78 | 79 | #endif -------------------------------------------------------------------------------- /northbound/grpc/vrg_node.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 gRPC authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | option java_multiple_files = true; 18 | option java_package = "io.grpc.vrgnodeservice"; 19 | option java_outer_classname = "VrgNodeProto"; 20 | 21 | import "google/protobuf/empty.proto"; 22 | 23 | package vrgnodeservice; 24 | 25 | service VrgService { 26 | //rpc ConnectHsi(HsiRequest) returns(google.protobuf.Empty) {} 27 | rpc ConnectHsi(HsiRequest) returns(HsiReply) {} 28 | rpc DisconnectHsi(HsiRequest) returns(HsiReply) {} 29 | rpc DhcpServerStart(DhcpServerRequest) returns(DhcpServerReply) {} 30 | rpc DhcpServerStop(DhcpServerRequest) returns(DhcpServerReply) {} 31 | rpc GetVrgSystemInfo(google.protobuf.Empty) returns(VrgSystemInfo) {} 32 | rpc GetVrgHsiInfo(google.protobuf.Empty) returns(VrgHsiInfo) {} 33 | rpc GetVrgDhcpInfo(google.protobuf.Empty) returns(VrgDhcpInfo) {} 34 | rpc GetNodeStatus(google.protobuf.Empty) returns(NodeStatus) {} 35 | } 36 | 37 | message HsiRequest { 38 | uint32 user_id = 1; 39 | bool force = 2; 40 | } 41 | 42 | message HsiReply { 43 | string status = 1; 44 | } 45 | 46 | message DhcpServerRequest { 47 | uint32 user_id = 1; 48 | } 49 | 50 | message DhcpServerReply { 51 | string status = 1; 52 | } 53 | 54 | message VrgBaseInfo { 55 | string vrg_version = 1; 56 | string build_date = 2; 57 | int64 uptime = 3; // in seconds 58 | string dpdk_version = 4; 59 | string dpdk_eal_args = 5; 60 | uint32 num_users = 6; 61 | } 62 | 63 | message NicDriverInfo { 64 | string driver_name = 1; 65 | string pci_addr = 2; 66 | bytes mac_addr = 3; 67 | } 68 | 69 | message Statistics{ 70 | uint64 rx_packets = 1; 71 | uint64 tx_packets = 2; 72 | uint64 rx_bytes = 3; 73 | uint64 tx_bytes = 4; 74 | uint64 rx_errors = 5; 75 | uint64 tx_errors = 6; 76 | uint64 rx_dropped = 7; 77 | } 78 | 79 | message VrgSystemInfo { 80 | VrgBaseInfo base_info = 1; 81 | repeated NicDriverInfo nics = 2; 82 | repeated Statistics stats = 3; 83 | } 84 | 85 | message NodeStatus { 86 | string node_os_version = 1; 87 | int64 node_uptime = 2; // in seconds 88 | string node_ip_info = 3; // mgmt ip/netmask 89 | bool healthy = 4; 90 | } 91 | 92 | message HsiInfo { 93 | uint32 user_id = 1; 94 | uint32 vlan_id = 2; 95 | string status = 3; 96 | string account = 4; 97 | string password = 5; 98 | uint32 session_id = 6; 99 | string ip_addr = 7; 100 | string gateway = 8; 101 | repeated string dnss = 9; 102 | } 103 | 104 | message VrgHsiInfo { 105 | repeated HsiInfo hsi_infos = 1; 106 | } 107 | 108 | message DhcpInfo { 109 | uint32 user_id = 1; 110 | string status = 2; 111 | string start_ip = 3; 112 | string end_ip = 4; 113 | string subnet_mask = 5; 114 | string gateway = 6; 115 | repeated string inuse_ips = 7; 116 | repeated string dnss = 8; 117 | } 118 | 119 | message VrgDhcpInfo { 120 | repeated DhcpInfo dhcp_infos = 1; 121 | } 122 | -------------------------------------------------------------------------------- /src/pppd/header.h: -------------------------------------------------------------------------------- 1 | #ifndef _HEADER_H_ 2 | #define _HEADER_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "../protocol.h" 9 | 10 | #define PPPOE_PHASE 0x1 11 | #define LCP_PHASE 0x2 12 | #define AUTH_PHASE 0x3 13 | #define IPCP_PHASE 0x4 14 | #define DATA_PHASE 0x5 15 | #define END_PHASE 0x0 16 | 17 | #define END_OF_LIST 0x0 18 | #define SERVICE_NAME 0x0101 19 | #define AC_NAME 0x0102 20 | #define HOST_UNIQ 0x0103 21 | #define AC_COOKIE 0x0104 22 | #define VENDER_SPECIFIC 0x0105 23 | #define RELAY_ID 0x0110 24 | #define SERVICE_NAME_ERROR 0x0201 25 | #define AC_SYSTEM_ERROR 0x0202 26 | #define GENERIC_ERROR 0x0203 27 | 28 | #define VER_TYPE 0x11 29 | #define PADI 0x9 30 | #define PADO 0x7 31 | #define PADR 0x19 32 | #define PADS 0x65 33 | #define PADT 0xa7 34 | #define PADM 0xd3 35 | #define SESSION_DATA 0x0 36 | 37 | #define LCP_PROTOCOL 0xc021 38 | #define PPP_IP_PROTOCOL 0x0021 39 | #define IPCP_PROTOCOL 0x8021 40 | #define PAP_PROTOCOL 0xc023 41 | #define CHAP_PROTOCOL 0xc223 42 | 43 | /* define for LCP/IPCP code */ 44 | #define CONFIG_REQUEST 0x1 45 | #define CONFIG_ACK 0x2 46 | #define CONFIG_NAK 0x3 47 | #define CONFIG_REJECT 0x4 48 | #define TERMIN_REQUEST 0x5 49 | #define TERMIN_ACK 0x6 50 | #define CODE_REJECT 0x7 51 | #define PROTO_REJECT 0x8 52 | #define ECHO_REQUEST 0x9 53 | #define ECHO_REPLY 0xa 54 | 55 | #define PAP_REQUEST 0x1 56 | #define PAP_ACK 0x2 57 | #define PAP_NAK 0x3 58 | 59 | #define CHAP_CHALLANGE 0x1 60 | #define CHAP_RESPONSE 0x2 61 | #define CHAP_SUCCESS 0x3 62 | #define CHAP_FAILURE 0x4 63 | 64 | /* define for LCP options */ 65 | #define MAGIC_NUM 0x5 66 | #define MRU 0x1 67 | #define AUTH 0x3 68 | 69 | /* define for IPCP options */ 70 | #define IP_ADDRESSES 0x1 71 | #define IP_COMPRESSION 0x2 72 | #define IP_ADDRESS 0x3 73 | #define PRIMARY_DNS 0x81 74 | #define SECOND_DNS 0x83 75 | 76 | #define MAX_RECV ETH_MTU - sizeof(pppoe_header_t) - sizeof(ppp_payload_t) - sizeof(vlan_header_t) 77 | #define MAX_RETRAN 10 78 | 79 | typedef struct pppoe_header { 80 | U8 ver_type; 81 | U8 code; 82 | U16 session_id; // network byte order 83 | U16 length; // host byte order 84 | }__rte_packed pppoe_header_t; 85 | 86 | typedef struct pppoe_header_tag { 87 | U16 type; // network byte order 88 | U16 length; // host byte order 89 | // depend on the type and length. 90 | U8 value[0]; 91 | }__rte_packed pppoe_header_tag_t; 92 | 93 | typedef struct ppp_header { 94 | U8 code; 95 | U8 identifier; 96 | U16 length; // network order, including ppp options length 97 | }__rte_packed ppp_header_t; 98 | 99 | typedef struct ppp_pap_ack_nak { 100 | U8 msg_length; 101 | U8 msg[0]; 102 | }__rte_packed ppp_pap_ack_nak_t; 103 | 104 | typedef struct ppp_chap_data { 105 | U8 val_size; 106 | U8 *val; 107 | U8 *name; 108 | }ppp_chap_data_t; 109 | 110 | typedef struct ppp_payload { 111 | U16 ppp_protocol; 112 | }__rte_packed ppp_payload_t; 113 | 114 | typedef struct ppp_options { 115 | U8 type; 116 | U8 length; 117 | U8 val[0]; 118 | }__rte_packed ppp_options_t; 119 | 120 | typedef struct pppoe_phase { 121 | pppoe_header_tag_t *pppoe_header_tag; 122 | U8 max_retransmit; 123 | U8 timer_counter; 124 | BOOL active; 125 | }__rte_cache_aligned pppoe_phase_t; 126 | 127 | typedef struct ppp_phase { 128 | U16 state; 129 | U16 event; 130 | ppp_payload_t ppp_payload; 131 | ppp_header_t ppp_hdr; 132 | ppp_options_t *ppp_options; 133 | U8 max_retransmit; 134 | U8 timer_counter; 135 | }__rte_cache_aligned ppp_phase_t; 136 | 137 | #endif 138 | -------------------------------------------------------------------------------- /src/pppd/nat.h: -------------------------------------------------------------------------------- 1 | #ifndef _NAT_H_ 2 | #define _NAT_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include "pppd.h" 25 | 26 | void nat_rule_timer(__attribute__((unused)) struct rte_timer *tim, PPP_INFO_t *s_ppp_ccb); 27 | 28 | static inline void nat_icmp_learning(struct rte_ether_hdr *eth_hdr, struct rte_ipv4_hdr *ip_hdr, struct rte_icmp_hdr *icmphdr, U32 *new_port_id, addr_table_t addr_table[]) 29 | { 30 | *new_port_id = rte_be_to_cpu_16(icmphdr->icmp_ident + (ip_hdr->src_addr) % 10000); 31 | if (*new_port_id > 0xffff) 32 | *new_port_id = *new_port_id / 0xffff + 1000; 33 | for(int j=1000,shift=0; jsrc_addr && addr_table[*new_port_id].dst_ip == ip_hdr->dst_addr)) 36 | return; 37 | shift++; 38 | (*new_port_id)++; 39 | } 40 | else { 41 | rte_wmb(); 42 | //addr_table[*new_port_id].is_fill = 1; 43 | rte_atomic16_set(&addr_table[*new_port_id].is_fill, 1); 44 | //s_ppp_ccb->addr_table[*new_port_id].shift = shift; 45 | break; 46 | } 47 | } 48 | rte_ether_addr_copy(ð_hdr->src_addr, &addr_table[*new_port_id].mac_addr); 49 | addr_table[*new_port_id].src_ip = ip_hdr->src_addr; 50 | addr_table[*new_port_id].dst_ip = ip_hdr->dst_addr; 51 | addr_table[*new_port_id].port_id = icmphdr->icmp_ident; 52 | } 53 | 54 | static inline void nat_udp_learning(struct rte_ether_hdr *eth_hdr, struct rte_ipv4_hdr *ip_hdr, struct rte_udp_hdr *udphdr, U32 *new_port_id, addr_table_t addr_table[]) 55 | { 56 | *new_port_id = rte_be_to_cpu_16(udphdr->src_port + (ip_hdr->src_addr) % 10000); 57 | if (*new_port_id > 0xffff) 58 | *new_port_id = *new_port_id / 0xffff + 1000; 59 | for(int j=1000,shift=0; jsrc_addr && addr_table[*new_port_id].dst_ip == ip_hdr->dst_addr)) 62 | return; 63 | shift++; 64 | (*new_port_id)++; 65 | } 66 | else { 67 | rte_wmb(); 68 | //addr_table[*new_port_id].is_fill = 1; 69 | rte_atomic16_set(&addr_table[*new_port_id].is_fill, 1); 70 | //s_ppp_ccb->addr_table[*new_port_id].shift = shift; 71 | break; 72 | } 73 | } 74 | rte_ether_addr_copy(ð_hdr->src_addr, &addr_table[*new_port_id].mac_addr); 75 | addr_table[*new_port_id].src_ip = ip_hdr->src_addr; 76 | addr_table[*new_port_id].dst_ip = ip_hdr->dst_addr; 77 | addr_table[*new_port_id].port_id = udphdr->src_port; 78 | } 79 | 80 | static inline void nat_tcp_learning(struct rte_ether_hdr *eth_hdr, struct rte_ipv4_hdr *ip_hdr, struct rte_tcp_hdr *tcphdr, U32 *new_port_id, addr_table_t addr_table[]) 81 | { 82 | *new_port_id = rte_be_to_cpu_16(tcphdr->src_port + (ip_hdr->src_addr) % 10000); 83 | if (*new_port_id > 0xffff) 84 | *new_port_id = *new_port_id / 0xffff + 1000; 85 | for(int j=1000,shift=0; jsrc_addr && addr_table[*new_port_id].dst_ip == ip_hdr->dst_addr)) 88 | return; 89 | shift++; 90 | (*new_port_id)++; 91 | } 92 | else { 93 | rte_wmb(); 94 | //addr_table[*new_port_id].is_fill = 1; 95 | rte_atomic16_set(&addr_table[*new_port_id].is_fill, 1); 96 | //s_ppp_ccb->addr_table[*new_port_id].shift = shift; 97 | break; 98 | } 99 | } 100 | rte_ether_addr_copy(ð_hdr->src_addr, &addr_table[*new_port_id].mac_addr); 101 | addr_table[*new_port_id].src_ip = ip_hdr->src_addr; 102 | addr_table[*new_port_id].dst_ip = ip_hdr->dst_addr; 103 | addr_table[*new_port_id].port_id = tcphdr->src_port; 104 | } 105 | 106 | #endif -------------------------------------------------------------------------------- /src/dhcpd/dhcpd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "../vrg.h" 8 | #include "dhcp_fsm.h" 9 | 10 | extern STATUS dhcp_fsm(dhcp_ccb_t *dhcp_ccb, U16 event); 11 | void release_lan_user(dhcp_ccb_t *dhcp_ccb); 12 | 13 | struct rte_ether_addr zero_mac; 14 | static VRG_t *vrg_ccb; 15 | 16 | STATUS dhcp_init(void *ccb) 17 | { 18 | vrg_ccb = (VRG_t *)ccb; 19 | vrg_ccb->dhcp_ccb = mmap(NULL, sizeof(dhcp_ccb_t)*vrg_ccb->user_count, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0); 20 | if (vrg_ccb->dhcp_ccb == MAP_FAILED) { 21 | perror("map mem"); 22 | vrg_ccb->dhcp_ccb = NULL; 23 | return ERROR; 24 | } 25 | dhcp_fsm_init(vrg_ccb); 26 | dhcp_ccb_t *dhcp_ccb = vrg_ccb->dhcp_ccb; 27 | 28 | for(int i=0; iuser_count; i++) { 32 | for(int j=0; jlan_ip; //default dhcp server ip is vRG lan ip 36 | dhcp_ccb[i].lan_user_info[j].lan_user_used = FALSE; 37 | rte_ether_addr_copy(&zero_mac, &dhcp_ccb[i].lan_user_info[j].mac_addr); 38 | dhcp_ccb[i].ip_pool[j].used = FALSE; 39 | //default ip pool start from lan_ip + 100 40 | dhcp_ccb[i].ip_pool[j].ip_addr = rte_cpu_to_be_32((rte_be_to_cpu_32(vrg_ccb->lan_ip) + j + 100)); 41 | rte_ether_addr_copy(&zero_mac, &dhcp_ccb[i].ip_pool[j].mac_addr); 42 | dhcp_ccb[i].lan_user_info[j].state = S_DHCP_INIT; 43 | rte_atomic16_init(&dhcp_ccb[i].dhcp_bool); 44 | } 45 | } 46 | 47 | return SUCCESS; 48 | } 49 | 50 | int dhcpd(struct rte_mbuf *single_pkt, struct rte_ether_hdr *eth_hdr, vlan_header_t *vlan_header, struct rte_ipv4_hdr *ip_hdr, struct rte_udp_hdr *udp_hdr, U16 user_index) 51 | { 52 | BIT16 event; 53 | dhcp_ccb_t *dhcp_ccb = vrg_ccb->dhcp_ccb; 54 | int lan_user_index = -1; 55 | 56 | if (user_index >= vrg_ccb->user_count) { 57 | rte_pktmbuf_free(single_pkt); 58 | return -1; 59 | } 60 | 61 | /* Pick one index from lan_user_info array and save it to dhcp_ccb */ 62 | for(int i=0; isrc_addr, &dhcp_ccb[user_index].lan_user_info[i].mac_addr); 66 | dhcp_ccb[user_index].lan_user_info[i].lan_user_used = TRUE; 67 | break; 68 | } 69 | else if (rte_is_same_ether_addr(ð_hdr->src_addr, &dhcp_ccb[user_index].lan_user_info[i].mac_addr)) { 70 | lan_user_index = dhcp_ccb[user_index].cur_lan_user_index = i; 71 | break; 72 | } 73 | } 74 | /* If dhcp ip pool is full, drop the packet */ 75 | if (lan_user_index < 0) { 76 | rte_pktmbuf_free(single_pkt); 77 | return -1; 78 | } 79 | /* If no more packet from the host, clear all information in dhcp_ccb */ 80 | rte_timer_stop(&dhcp_ccb[user_index].lan_user_info[lan_user_index].timer); 81 | rte_timer_reset(&dhcp_ccb[user_index].lan_user_info[lan_user_index].timer, LEASE_TIMEOUT * 2 * rte_get_timer_hz(), SINGLE, vrg_ccb->lcore.timer_thread, (rte_timer_cb_t)release_lan_user, &dhcp_ccb[user_index]); 82 | 83 | event = dhcp_decode(&dhcp_ccb[user_index], eth_hdr, vlan_header, ip_hdr, udp_hdr); 84 | if (event < 0) { 85 | release_lan_user(&dhcp_ccb[user_index]); 86 | rte_pktmbuf_free(single_pkt); 87 | return -1; 88 | } 89 | else if (event == 0) 90 | return 0; 91 | if (dhcp_fsm(&dhcp_ccb[user_index], event) == FALSE) { 92 | release_lan_user(&dhcp_ccb[user_index]); 93 | rte_pktmbuf_free(single_pkt); 94 | return -1; 95 | } 96 | single_pkt->data_len = single_pkt->pkt_len = sizeof(struct rte_ether_hdr) + sizeof(vlan_header_t) + sizeof(struct rte_ipv4_hdr) + rte_be_to_cpu_16(dhcp_ccb[user_index].ip_hdr->total_length); 97 | return 1; 98 | } 99 | 100 | void release_lan_user(dhcp_ccb_t *dhcp_ccb) 101 | { 102 | U8 lan_user_index = dhcp_ccb->cur_lan_user_index; 103 | 104 | dhcp_ccb->ip_pool[dhcp_ccb->cur_ip_pool_index].used = FALSE; 105 | dhcp_ccb->lan_user_info[lan_user_index].lan_user_used = FALSE; 106 | rte_ether_addr_copy(&zero_mac, &dhcp_ccb->lan_user_info[lan_user_index].mac_addr); 107 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Virtualized residential gateway (vRG) implementation using DPDK 2 | 3 | [![BSD license](https://img.shields.io/badge/License-BSD-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) 4 | [![vRG ci](https://github.com/w180112/vRG_DPDK/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/w180112/vRG_DPDK/actions/workflows/ci.yml) 5 | 6 | In nowadays high speed virtualized nerwork, tranditional network mechanism has no longer satisfied our requirement. In home network virtualization many data plane features, e.g.: NAT and PPPoE client, will be de-coupled to cloud NFV infrastructure. However, the perfoemance of data plane is always the main point of our concern. Therefore, a vRG system that make PPPoE client and NAT can be used in virtualization is purposed. By the powerful DPDK, all packets can be forwarded in high speed network. 7 | 8 | ## System required: 9 | 10 | Intel DPDK 22.11, at least 2G ram, 8 cpu cores. 11 | 12 | Package required: make gcc pip3 pyelftools pkg-config meson libnuma-dev autoconf libconfig-dev 13 | 14 | ## How to use: 15 | 16 | In this project 2 DPDK ethernet ports are needed, the first is used to receive packets from/send packets to LAN port and the second is used to receive packets from/send packets to WAN port. 17 | 18 | Git clone this repository 19 | 20 | # git clone https://github.com/w180112/vRG_DPDK.git 21 | 22 | Type 23 | 24 | # cd vRG 25 | # git submodule update --init --recursive 26 | 27 | For first time build, please use boot.sh to build DPDK library, libutil and vRG 28 | 29 | # ./boot.sh 30 | 31 | For just vRG build, clean, install and uninstall, please use makefile 32 | 33 | # make && make install 34 | # make clean && make uninstall 35 | 36 | Then 37 | 38 | # vrg 39 | 40 | e.g. 41 | 42 | # vrg -l 0-7 -n 4 43 | 44 | For using vRG in Docker, 45 | 46 | # docker build --no-cache -t vrg:latest . 47 | # mount -t hugetlbfs -o pagesize=1G none /dev/hugepages1G 48 | # docker run -d --net=host --privileged -v /sys/bus/pci/devices:/sys/bus/pci/devices \ 49 | -v /sys/kernel/mm/hugepages:/sys/kernel/mm/hugepages -v /sys/devices/system/node:/sys/devices/system/node -v /dev:/dev vrg:latest bash 50 | 51 | After vRG system started, there is a CLI. User can input "?" command to show available commands. 52 | 53 | Use command ***connect*** or ***disconnect*** to determine which user start/stop a PPPoE connection, e.g.: to start all subscribers PPPoE connection defined in ***vRG-setup*** file. 54 | 55 | vRG> connect all 56 | 57 | To start specific subscriber 1 PPPoE connection. 58 | 59 | vRG> connect 1 60 | 61 | To disconnect all subscribers PPPoE connection. 62 | 63 | vRG> disconnect all 64 | 65 | To start specific subscriber 1 DHCP server. 66 | 67 | vRG> dhcp-server start 1 68 | 69 | To stop all subscribers DHCP server. 70 | 71 | vRG> dhcp-server stop all 72 | 73 | For hugepages, NIC binding and other system configuration, please refer to Intel DPDK documentation: [DPDK doc](http://doc.dpdk.org/guides/linux_gsg/) 74 | 75 | ## Note: 76 | 77 | 1. The vRG system only support 3 LCP options, PAP authentication, Magic Number, Max receive unit so far. 78 | 2. Users behind vRG should use DHCP to get IP address or set the default gateway address 192.168.2.1 to their end device. 79 | 3. The default gateway ip address can be configured in ***config.cfg***. 80 | 4. Administrator can assign how many subscriber PPPoE sessions will be established, the maximum support sessions are 4094, but only 20 sessions have been tested so far. 81 | 5. In default configurationin ***config.cfg*** file, there are only 20 vRG subscriber PPPoE sessions. You can just modify the value ***UserCount*** in this file. For example, there will be 4 subscriber PPPoE connection while the value is changed to 4. 82 | 6. In data plane, default subscriber 1 uses single tag vlan 2, subscriber 2 uses single tag vlan 3. All data plane packets received at vRG system should include a single tag vlan. If you don't need to run vRG system in VLAN environment, config ***NonVlanMode*** in ***config.cfg*** file to 1(Note: non-vlan mode only support 1 subscriber PPPoE connection at the same time). 83 | 7. All DPDK EAL lcores should be on same CPU socket. 84 | 85 | ## Test environment: 86 | 87 | 1. Ubuntu 24.04 with Mellanox CX4 Lx virtual function and RHEL 9.2 with Intel X710 NIC SR-I/OV virtual function 88 | 2. Xeon Platinum 8124 / Xeon Gold 8255 with ECC RAM server 89 | 3. Successfully test control plane and data plane with CHT(Chunghwa Telecom Co., Ltd.) BRAS, open source RP-PPPoE and Spirent test center PPPoE server 90 | 4. Intel DPDK 22.11 91 | 92 | ## Example use case: 93 | 94 | ![image](https://github.com/w180112/vRG/blob/master/topo.png) 95 | 96 | ## TODO: 97 | 98 | 1. Add unit tests 99 | 2. Split ccb for each CPU core 100 | 3. Support DDP 101 | 4. Add LCP exception 102 | -------------------------------------------------------------------------------- /src/init.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "pppd/pppd.h" 8 | #include "dhcpd/dhcp_codec.h" 9 | #include "dp.h" 10 | #include "init.h" 11 | #include "vrg.h" 12 | #include "dbg.h" 13 | #include "version.h" 14 | 15 | #define NUM_MBUFS 8191 16 | #define MBUF_CACHE_SIZE 512 17 | #define RING_SIZE 16384 18 | 19 | struct rte_ring *rte_ring, *gateway_q, *uplink_q, *downlink_q; 20 | struct rte_mempool *direct_pool[PORT_AMOUNT]; 21 | struct rte_mempool *indirect_pool[PORT_AMOUNT]; 22 | 23 | extern int rte_ethtool_get_drvinfo(U16 port_id, struct ethtool_drvinfo *drv_info); 24 | 25 | struct nic_info vendor[] = { 26 | { "mlx5_pci", MLX5 }, 27 | { "net_ixgbe", IXGBE }, 28 | { "net_vmxnet3", VMXNET3 }, 29 | { "net_ixgbe_vf", IXGBEVF }, 30 | { "net_i40e", I40E }, 31 | { "net_i40e_vf", I40EVF }, 32 | { "", 0 } 33 | }; 34 | 35 | static int init_mem(VRG_t *vrg_ccb) 36 | { 37 | char buf[PATH_MAX]; 38 | struct rte_mempool *mp; 39 | //int socket; 40 | 41 | /* Creates a new mempool in memory to hold the mbufs. */ 42 | for(int i=0; ifp, NULL, NULL, "Creating direct mempool on port %i", i); 45 | snprintf(buf, sizeof(buf), "pool_direct_%i", i); 46 | mp = rte_pktmbuf_pool_create(buf, NUM_MBUFS, MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); 47 | if (mp == NULL) { 48 | VRG_LOG(ERR, vrg_ccb->fp, NULL, NULL, "Cannot create direct mempool"); 49 | return rte_errno; 50 | } 51 | direct_pool[i] = mp; 52 | } 53 | 54 | if (indirect_pool[i] == NULL) { 55 | VRG_LOG(INFO, vrg_ccb->fp, NULL, NULL, "Creating indirect mempool on port %i", i); 56 | snprintf(buf, sizeof(buf), "pool_indirect_%i", i); 57 | 58 | mp = rte_pktmbuf_pool_create(buf, NUM_MBUFS, MBUF_CACHE_SIZE, 0, 0, rte_socket_id()); 59 | if (mp == NULL) { 60 | VRG_LOG(ERR, vrg_ccb->fp, NULL, NULL, "Cannot create indirect mempool"); 61 | return rte_errno; 62 | } 63 | indirect_pool[i] = mp; 64 | } 65 | } 66 | 67 | return 0; 68 | } 69 | 70 | static int init_ring(void) 71 | { 72 | rte_ring = rte_ring_create("state_machine",RING_SIZE,rte_socket_id(),0); 73 | if (!rte_ring) 74 | return rte_errno; 75 | gateway_q = rte_ring_create("rg-function",RING_SIZE,rte_socket_id(),0); 76 | if (!gateway_q) 77 | return rte_errno; 78 | uplink_q = rte_ring_create("upstream",RING_SIZE,rte_socket_id(),0); 79 | if (!uplink_q) 80 | return rte_errno; 81 | downlink_q = rte_ring_create("downstream",RING_SIZE,rte_socket_id(),0); 82 | if (!downlink_q) 83 | return rte_errno; 84 | 85 | return 0; 86 | } 87 | 88 | int init_port(VRG_t *vrg_ccb) 89 | { 90 | struct ethtool_drvinfo dev_info; 91 | U8 portid; 92 | 93 | rte_eth_macaddr_get(0, &vrg_ccb->nic_info.hsi_lan_mac); 94 | rte_eth_macaddr_get(1, &vrg_ccb->nic_info.hsi_wan_src_mac); 95 | 96 | /* Initialize all ports. */ 97 | for(portid=0; portid<2; portid++) { 98 | memset(&dev_info, 0, sizeof(dev_info)); 99 | if (rte_ethtool_get_drvinfo(portid, &dev_info)) { 100 | VRG_LOG(ERR, vrg_ccb->fp, NULL, NULL, "Error getting info for port %i", portid); 101 | return rte_errno; 102 | } 103 | for(int i=0; vendor[i].vendor_id; i++) { 104 | if (strcmp((const char *)dev_info.driver, vendor[i].vendor_name) == 0) { 105 | vrg_ccb->nic_info.vendor_id = vendor[i].vendor_id; 106 | strcpy(vrg_ccb->nic_info.vendor_name, vendor[i].vendor_name); 107 | break; 108 | } 109 | } 110 | 111 | VRG_LOG(INFO, vrg_ccb->fp, NULL, NULL, "Port %i driver: %s (ver: %s)", portid, dev_info.driver, dev_info.version); 112 | VRG_LOG(INFO, vrg_ccb->fp, NULL, NULL, "firmware-version: %s", dev_info.fw_version); 113 | VRG_LOG(INFO, vrg_ccb->fp, NULL, NULL, "bus-info: %s", dev_info.bus_info); 114 | 115 | if (PORT_INIT(vrg_ccb, portid) != 0) { 116 | VRG_LOG(ERR, vrg_ccb->fp, NULL, NULL, "Cannot init port %"PRIu8 "", portid); 117 | return -1; 118 | } 119 | } 120 | 121 | vrg_ccb->vrg_switch = vrg_malloc(vrg_feature_switch_t, vrg_ccb->user_count * 122 | sizeof(vrg_feature_switch_t), 0); 123 | if (vrg_ccb->vrg_switch == NULL) { 124 | VRG_LOG(ERR, vrg_ccb->fp, NULL, NULL, "Cannot allocate memory for vrg_switch"); 125 | return -1; 126 | } 127 | for(int i=0; iuser_count; i++) { 128 | vrg_ccb->vrg_switch[i].is_hsi_enable = VRG_SUBMODULE_IS_TERMINATED; 129 | vrg_ccb->vrg_switch[i].is_dhcp_server_enable = VRG_SUBMODULE_IS_TERMINATED; 130 | } 131 | 132 | vrg_ccb->version = GIT_COMMIT_ID; 133 | vrg_ccb->build_date = BUILD_TIME; 134 | 135 | return 0; 136 | } 137 | 138 | int sys_init(VRG_t *vrg_ccb) 139 | { 140 | int ret; 141 | 142 | ret = init_mem(vrg_ccb); 143 | if (ret) 144 | return ret; 145 | ret = init_ring(); 146 | if (ret) 147 | return ret; 148 | 149 | signal(SIGINT, (__sighandler_t)vrg_interrupt); 150 | 151 | /* init RTE timer library */ 152 | rte_timer_subsystem_init(); 153 | 154 | ret = init_port(vrg_ccb); 155 | if (ret != 0) 156 | return ret; 157 | 158 | rte_timer_init(&vrg_ccb->link); 159 | return 0; 160 | } 161 | -------------------------------------------------------------------------------- /src/dhcpd/dhcp_fsm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../dbg.h" 3 | #include "../vrg.h" 4 | #include "dhcp_fsm.h" 5 | 6 | extern STATUS build_dhcp_offer(dhcp_ccb_t *dhcp_ccb); 7 | extern STATUS build_dhcp_ack(dhcp_ccb_t *dhcp_ccb); 8 | extern STATUS build_dhcp_nak(dhcp_ccb_t *dhcp_ccb); 9 | 10 | STATUS A_create_offer_event(struct rte_timer *tim, dhcp_ccb_t *dhcp_ccb); 11 | STATUS A_send_dhcp_offer(__attribute__((unused)) struct rte_timer *tim, dhcp_ccb_t *dhcp_ccb); 12 | STATUS A_wait_request_timer(struct rte_timer *tim, dhcp_ccb_t *dhcp_ccb); 13 | STATUS A_send_dhcp_ack(struct rte_timer *tim, dhcp_ccb_t *dhcp_ccb); 14 | STATUS A_send_dhcp_nak(struct rte_timer *tim, dhcp_ccb_t *dhcp_ccb); 15 | STATUS A_wait_lease_timer(struct rte_timer *tim, dhcp_ccb_t *dhcp_ccb); 16 | STATUS A_release(struct rte_timer *tim, dhcp_ccb_t *dhcp_ccb); 17 | 18 | static VRG_t *vrg_ccb; 19 | 20 | tDHCP_STATE_TBL dhcp_fsm_tbl[9] = { 21 | /*////////////////////////////////////////////////////////////////////////////////// 22 | STATE EVENT NEXT-STATE HANDLER 23 | ///////////////////////////////////////////////////////////////////////////////////\*/ 24 | { S_DHCP_INIT, E_DISCOVER, S_DHCP_OFFER_SENT, { A_send_dhcp_offer, A_wait_request_timer, 0 }}, 25 | 26 | { S_DHCP_OFFER_SENT, E_DISCOVER, S_DHCP_OFFER_SENT, { A_send_dhcp_offer, A_wait_request_timer, 0 }}, 27 | 28 | { S_DHCP_OFFER_SENT, E_TIMEOUT, S_DHCP_INIT, { A_release, 0 }}, 29 | 30 | { S_DHCP_OFFER_SENT, E_GOOD_REQUEST, S_DHCP_ACK_SENT, { A_send_dhcp_ack, A_wait_lease_timer, 0 }}, 31 | 32 | { S_DHCP_REQUEST_RECV, E_BAD_REQUEST, S_DHCP_NAK_SENT, { A_send_dhcp_nak, 0 }}, 33 | 34 | { S_DHCP_ACK_SENT, E_TIMEOUT, S_DHCP_INIT, { A_release, 0 }}, 35 | 36 | { S_DHCP_ACK_SENT, E_RELEASE, S_DHCP_INIT, { A_release, 0 }}, 37 | 38 | { S_DHCP_ACK_SENT, E_GOOD_REQUEST, S_DHCP_ACK_SENT, { A_send_dhcp_ack, A_wait_lease_timer, 0 }}, 39 | 40 | { S_DHCP_INVLD, 0, 0, {0}} 41 | 42 | }; 43 | 44 | /*********************************************************************** 45 | * dhcp_fsm 46 | * 47 | * purpose : finite state machine. 48 | * input : dhcp_timer - timer 49 | * dhcp_ccb - user connection info. 50 | * event - 51 | * return : error status 52 | ***********************************************************************/ 53 | STATUS dhcp_fsm(dhcp_ccb_t *dhcp_ccb, U16 event) 54 | { 55 | register int i,j; 56 | BOOL retval; 57 | char str1[30],str2[30]; 58 | 59 | /* Find a matched state */ 60 | for(i=0; dhcp_fsm_tbl[i].state!=S_DHCP_INVLD; i++) 61 | if (dhcp_fsm_tbl[i].state == dhcp_ccb->lan_user_info[dhcp_ccb->cur_lan_user_index].state) 62 | break; 63 | VRG_LOG(INFO, vrg_ccb->fp, (U8 *)dhcp_ccb, DHCPLOGMSG, "Current state is %s\n", DHCP_state2str(dhcp_fsm_tbl[i].state)); 64 | if (dhcp_fsm_tbl[i].state == S_DHCP_INVLD) { 65 | VRG_LOG(INFO, vrg_ccb->fp, (U8 *)dhcp_ccb, DHCPLOGMSG, "Error! unknown state(%d) specified for the event(%d)\n", 66 | dhcp_ccb->lan_user_info[dhcp_ccb->cur_lan_user_index].state, event); 67 | return FALSE; 68 | } 69 | 70 | /* 71 | * Find a matched event in a specific state. 72 | * Note : a state can accept several events. 73 | */ 74 | for(;dhcp_fsm_tbl[i].state==dhcp_ccb->lan_user_info[dhcp_ccb->cur_lan_user_index].state; i++) 75 | if (dhcp_fsm_tbl[i].event == event) 76 | break; 77 | 78 | if (dhcp_fsm_tbl[i].state != dhcp_ccb->lan_user_info[dhcp_ccb->cur_lan_user_index].state) { /* search until meet the next state */ 79 | VRG_LOG(INFO, vrg_ccb->fp, (U8 *)dhcp_ccb, DHCPLOGMSG, "error! invalid event(%d) in state(%s)\n", 80 | event, DHCP_state2str(dhcp_ccb->lan_user_info[dhcp_ccb->cur_lan_user_index].state)); 81 | return FALSE; 82 | } 83 | 84 | /* Correct state found */ 85 | if (dhcp_ccb->lan_user_info[dhcp_ccb->cur_lan_user_index].state != dhcp_fsm_tbl[i].next_state) { 86 | strcpy(str1,DHCP_state2str(dhcp_ccb->lan_user_info[dhcp_ccb->cur_lan_user_index].state)); 87 | strcpy(str2,DHCP_state2str(dhcp_fsm_tbl[i].next_state)); 88 | VRG_LOG(INFO, vrg_ccb->fp, (U8 *)dhcp_ccb, DHCPLOGMSG, "dhcp state changed from %s to %s\n",str1,str2); 89 | dhcp_ccb->lan_user_info[dhcp_ccb->cur_lan_user_index].state = dhcp_fsm_tbl[i].next_state; 90 | } 91 | 92 | for(j=0; dhcp_fsm_tbl[i].hdl[j]; j++) { 93 | dhcp_ccb->lan_user_info[dhcp_ccb->cur_lan_user_index].timer_counter = 10; 94 | retval = (*dhcp_fsm_tbl[i].hdl[j])(&dhcp_ccb->lan_user_info[dhcp_ccb->cur_lan_user_index].timer, dhcp_ccb); 95 | if (retval == FALSE) 96 | return FALSE; 97 | } 98 | return TRUE; 99 | } 100 | 101 | STATUS A_send_dhcp_offer(__attribute__((unused)) struct rte_timer *tim, dhcp_ccb_t *dhcp_ccb) 102 | { 103 | if (build_dhcp_offer(dhcp_ccb) == TRUE) 104 | return TRUE; 105 | else 106 | return FALSE; 107 | } 108 | 109 | void request_timer(struct rte_timer *tim, dhcp_ccb_t *dhcp_ccb) 110 | { 111 | dhcp_fsm(dhcp_ccb, E_TIMEOUT); 112 | } 113 | 114 | STATUS A_wait_request_timer(struct rte_timer *tim, dhcp_ccb_t *dhcp_ccb) 115 | { 116 | rte_timer_stop(tim); 117 | rte_timer_reset(tim, 5 * rte_get_timer_hz(), SINGLE, vrg_ccb->lcore.timer_thread, (rte_timer_cb_t)request_timer, dhcp_ccb); 118 | return TRUE; 119 | } 120 | 121 | STATUS A_send_dhcp_ack(struct rte_timer *tim, dhcp_ccb_t *dhcp_ccb) 122 | { 123 | if (build_dhcp_ack(dhcp_ccb) == TRUE) 124 | return TRUE; 125 | else 126 | return FALSE; 127 | } 128 | 129 | STATUS A_send_dhcp_nak(struct rte_timer *tim, dhcp_ccb_t *dhcp_ccb) 130 | { 131 | if (build_dhcp_nak(dhcp_ccb) == TRUE) 132 | return TRUE; 133 | else 134 | return FALSE; 135 | } 136 | 137 | void lease_timer(struct rte_timer *tim, dhcp_ccb_t *dhcp_ccb) 138 | { 139 | dhcp_fsm(dhcp_ccb, E_TIMEOUT); 140 | } 141 | 142 | STATUS A_wait_lease_timer(struct rte_timer *tim, dhcp_ccb_t *dhcp_ccb) 143 | { 144 | dhcp_ccb_t dhcp_ccb_for_timer = *dhcp_ccb; 145 | 146 | rte_timer_stop(tim); 147 | rte_timer_reset(tim, LEASE_TIMEOUT * rte_get_timer_hz(), SINGLE, vrg_ccb->lcore.timer_thread, (rte_timer_cb_t)lease_timer, &dhcp_ccb_for_timer); 148 | 149 | return TRUE; 150 | } 151 | 152 | STATUS A_release(struct rte_timer *tim, dhcp_ccb_t *dhcp_ccb) 153 | { 154 | dhcp_ccb->ip_pool[dhcp_ccb->cur_ip_pool_index].used = FALSE; 155 | return TRUE; 156 | } 157 | 158 | void dhcp_fsm_init(VRG_t *ccb) 159 | { 160 | vrg_ccb = ccb; 161 | } -------------------------------------------------------------------------------- /src/dbg.c: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | * DBG.C 3 | * 4 | * Debug methods for ppp detection 5 | * 6 | * Created by THE on JUN 11,'19 7 | **************************************************************************/ 8 | 9 | #include 10 | #include 11 | #include "pppd/pppd.h" 12 | #include "pppd/fsm.h" 13 | #include "dhcpd/dhcp_fsm.h" 14 | #include "dbg.h" 15 | 16 | #define DBG_VRG_MSG_LEN 256 17 | #define LOGGER_BUF_LEN 1024 18 | 19 | static VRG_t *vrg_ccb; 20 | 21 | char *loglvl2str(U8 level) 22 | { 23 | switch (level) { 24 | case LOGDBG: 25 | return "DBG"; 26 | case LOGINFO: 27 | return "INFO"; 28 | case LOGWARN: 29 | return "WARN"; 30 | case LOGERR: 31 | return "ERR"; 32 | default: 33 | return "UNKNOWN"; 34 | } 35 | } 36 | 37 | U8 logstr2lvl(const char *log_str) 38 | { 39 | if (strcmp(log_str, "DBG") == 0) { 40 | return LOGDBG; 41 | } 42 | if (strcmp(log_str, "INFO") == 0) { 43 | return LOGINFO; 44 | } 45 | if (strcmp(log_str, "WARN") == 0) { 46 | return LOGWARN; 47 | } 48 | if (strcmp(log_str, "ERR") == 0) { 49 | return LOGERR; 50 | } 51 | 52 | return LOGUNKNOWN; 53 | } 54 | 55 | /*------------------------------------------------------------------- 56 | * PPP_state2str 57 | * 58 | * input : state 59 | * return: string of corresponding state value 60 | *------------------------------------------------------------------*/ 61 | char *PPP_state2str(U16 state) 62 | { 63 | static struct { 64 | PPP_STATE state; 65 | char str[20]; 66 | } ppp_state_desc_tbl[] = { 67 | { S_INIT, "INIT" }, 68 | { S_STARTING, "STARTING" }, 69 | { S_CLOSED, "CLOSED" }, 70 | { S_STOPPED, "STOPPED" }, 71 | { S_CLOSING, "CLOSING" }, 72 | { S_STOPPING, "STOPPONG" }, 73 | { S_REQUEST_SENT, "REQUEST_SENT" }, 74 | { S_ACK_RECEIVED, "ACK_RECEIVED" }, 75 | { S_ACK_SENT, "ACK_SENT" }, 76 | { S_OPENED, "OPENED" }, 77 | { S_INVLD, "Unknwn" }, 78 | }; 79 | 80 | U8 i; 81 | 82 | for(i=0; ppp_state_desc_tbl[i].state != S_INVLD; i++) { 83 | if (ppp_state_desc_tbl[i].state == state) break; 84 | } 85 | if (ppp_state_desc_tbl[i].state == S_INVLD) 86 | return NULL; 87 | 88 | return ppp_state_desc_tbl[i].str; 89 | } 90 | 91 | /*------------------------------------------------------------------- 92 | * PPP_event2str 93 | * 94 | * input : event 95 | * return: string of corresponding event value 96 | *------------------------------------------------------------------*/ 97 | char *PPP_event2str(U16 event) 98 | { 99 | static struct { 100 | PPP_EVENT_TYPE event; 101 | char str[64]; 102 | } ppp_event_desc_tbl[] = { 103 | { E_UP, "UP" }, 104 | { E_DOWN, "DOWN" }, 105 | { E_OPEN, "OPEN" }, 106 | { E_CLOSE, "CLOSE" }, 107 | { E_TIMEOUT_COUNTER_POSITIVE, "TIMEOUT_COUNTER_POSITIVE" }, 108 | { E_TIMEOUT_COUNTER_EXPIRED, "TIMEOUT_COUNTER_EXPIRED" }, 109 | { E_RECV_GOOD_CONFIG_REQUEST, "RECV_GOOD_CONFIG_REQUEST" }, 110 | { E_RECV_BAD_CONFIG_REQUEST, "RECV_BAD_CONFIG_REQUEST" }, 111 | { E_RECV_CONFIG_ACK, "RECV_CONFIG_ACK" }, 112 | { E_RECV_CONFIG_NAK_REJ, "RECV_CONFIG_NAK_REJECT" }, 113 | { E_RECV_TERMINATE_REQUEST, "RECV_TERMINATE_REQUEST" }, 114 | { E_RECV_TERMINATE_ACK, "RECV_TERMINATE_ACK" }, 115 | { E_RECV_UNKNOWN_CODE, "RECV_UNKNOWN_CODE" }, 116 | { E_RECV_GOOD_CODE_PROTOCOL_REJECT, "RECV_GOOD_CODE_PROTOCOL_REJECT" }, 117 | { E_RECV_BAD_CODE_PROTOCOL_REJECT, "RECV_BAD_CODE_PROTOCOL_REJECT" }, 118 | { E_RECV_ECHO_REPLY_REQUEST_DISCARD_REQUEST, "RECV_ECHO_REPLY_REQUEST_DISCARD_REQUEST" }, 119 | { E_UNKNOWN, "UNKNOWN" }, 120 | }; 121 | 122 | U8 i; 123 | 124 | for(i=0; ppp_event_desc_tbl[i].event != E_UNKNOWN; i++) { 125 | if (ppp_event_desc_tbl[i].event == event) break; 126 | } 127 | 128 | return ppp_event_desc_tbl[i].str; 129 | } 130 | 131 | /*------------------------------------------------------------------- 132 | * DHCP_state2str 133 | * 134 | * input : state 135 | * return: string of corresponding state value 136 | *------------------------------------------------------------------*/ 137 | char *DHCP_state2str(U16 state) 138 | { 139 | static struct { 140 | DHCP_STATE state; 141 | char str[20]; 142 | } dhcp_state_desc_tbl[] = { 143 | { S_DHCP_INIT, "DHCP INIT" }, 144 | { S_DHCP_DISCOVER_RECV, "DHCP DISCOVERY RECV" }, 145 | { S_DHCP_OFFER_SENT, "DHCP OFFER SENT" }, 146 | { S_DHCP_REQUEST_RECV, "DHCP REQUEST RECV" }, 147 | { S_DHCP_ACK_SENT, "DHCP ACK SENT" }, 148 | { S_DHCP_NAK_SENT, "DHCP NAK SENT" }, 149 | { S_DHCP_INVLD, "DHCP INVALID" }, 150 | }; 151 | 152 | U8 i; 153 | 154 | for(i=0; dhcp_state_desc_tbl[i].state != S_DHCP_INVLD; i++) { 155 | if (dhcp_state_desc_tbl[i].state == state) break; 156 | } 157 | if (dhcp_state_desc_tbl[i].state == S_DHCP_INVLD) 158 | return NULL; 159 | 160 | return dhcp_state_desc_tbl[i].str; 161 | } 162 | 163 | void PPPLOGMSG(void *ccb, char *buf) 164 | { 165 | PPP_INFO_t *s_ppp_ccb = (PPP_INFO_t *)ccb; 166 | if (s_ppp_ccb) { 167 | sprintf(buf, "pppd> Session id [%x] ", rte_be_to_cpu_16(s_ppp_ccb->session_id)); 168 | } 169 | } 170 | 171 | void DHCPLOGMSG(void *ccb, char *buf) 172 | { 173 | dhcp_ccb_t *dhcp_ccb = (dhcp_ccb_t *)ccb; 174 | if (dhcp_ccb) { 175 | sprintf(buf,"dhcpd> ip pool index, user index[%u, %u, %s] ", dhcp_ccb->cur_ip_pool_index, dhcp_ccb->cur_lan_user_index, DHCP_state2str(dhcp_ccb->lan_user_info[dhcp_ccb->cur_lan_user_index].state)); 176 | } 177 | } 178 | 179 | /*************************************************** 180 | * LOGGER: 181 | ***************************************************/ 182 | void LOGGER(U8 level, char *filename, int line_num, FILE *log_fp, void *ccb, void (*ccb2str)(void *, char *), const char *fmt,...) 183 | { 184 | va_list ap; /* points to each unnamed arg in turn */ 185 | char buf[LOGGER_BUF_LEN], protocol_buf[LOGGER_BUF_LEN-100], msg[DBG_VRG_MSG_LEN]; 186 | 187 | protocol_buf[0] = '\0'; 188 | msg[0] = 0; 189 | buf[0] = 0; 190 | 191 | //user offer level must > system requirement 192 | if (vrg_ccb->loglvl > level) 193 | return; 194 | 195 | va_start(ap, fmt); /* set ap pointer to 1st unnamed arg */ 196 | vsnprintf(msg, DBG_VRG_MSG_LEN, fmt, ap); 197 | 198 | if (ccb2str) 199 | ccb2str(ccb, protocol_buf); 200 | 201 | snprintf(buf, sizeof(buf)-1, "vRG[%s]: %s:%d> %s", loglvl2str(level), filename, line_num, protocol_buf); 202 | strncat(buf, msg, sizeof(buf)-1); 203 | va_end(ap); 204 | 205 | buf[sizeof(buf)-1] = '\0'; 206 | if (vrg_ccb->loglvl == LOGDBG) 207 | fprintf(stdout, "%s\n", buf); 208 | if (log_fp != NULL) { 209 | fwrite(buf, sizeof(char), strlen(buf), log_fp); 210 | char *newline = "\n"; 211 | fwrite(newline, sizeof(char), strlen(newline), log_fp); 212 | fflush(log_fp); 213 | } 214 | } 215 | 216 | void dbg_init(void *ccb) 217 | { 218 | vrg_ccb = (VRG_t *)ccb; 219 | } 220 | -------------------------------------------------------------------------------- /src/pppd/pppd.c: -------------------------------------------------------------------------------- 1 | /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ 2 | PPPD.C 3 | 4 | - purpose : for ppp detection 5 | 6 | Designed by THE on Jan 14, 2019 7 | /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/ 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 "pppd.h" 22 | #include "fsm.h" 23 | #include "../dp.h" 24 | #include "../dbg.h" 25 | #include "../init.h" 26 | #include "../dp_flow.h" 27 | #include "../dhcpd/dhcpd.h" 28 | #include "../vrg.h" 29 | #include "../utils.h" 30 | 31 | U32 ppp_interval; 32 | static VRG_t *vrg_ccb; 33 | 34 | extern STATUS PPP_FSM(struct rte_timer *ppp, PPP_INFO_t *ppp_ccb, U16 event); 35 | 36 | /** 37 | * @brief pppoe connection closing processing function 38 | * 39 | * @param s_ppp_ccb 40 | */ 41 | void PPP_bye(PPP_INFO_t *s_ppp_ccb) 42 | { 43 | rte_timer_stop(&(s_ppp_ccb->ppp)); 44 | rte_timer_stop(&(s_ppp_ccb->pppoe)); 45 | rte_timer_stop(&(s_ppp_ccb->ppp_alive)); 46 | rte_atomic16_cmpset((volatile uint16_t *)&s_ppp_ccb->dp_start_bool.cnt, (BIT16)1, (BIT16)0); 47 | switch(s_ppp_ccb->phase) { 48 | case END_PHASE: 49 | rte_atomic16_set(&s_ppp_ccb->ppp_bool, 0); 50 | s_ppp_ccb->ppp_processing = FALSE; 51 | if ((--vrg_ccb->cur_user) == 0) { 52 | if (vrg_ccb->quit_flag == TRUE) { 53 | rte_ring_free(rte_ring); 54 | rte_ring_free(uplink_q); 55 | rte_ring_free(downlink_q); 56 | rte_ring_free(gateway_q); 57 | fclose(vrg_ccb->fp); 58 | close(vrg_ccb->unix_sock_fd); 59 | munmap(vrg_ccb->ppp_ccb, sizeof(PPP_INFO_t)*vrg_ccb->user_count); 60 | munmap(vrg_ccb->dhcp_ccb, sizeof(dhcp_ccb_t)*vrg_ccb->user_count); 61 | //rte_mempool_put_bulk(vrg_ccb.ppp_ccb_mp, (void *const *)&vrg_ccb.ppp_ccb, user_count); 62 | //rte_mempool_free(vrg_ccb.ppp_ccb_mp); 63 | #ifdef RTE_LIBRTE_PDUMP 64 | /*uninitialize packet capture framework */ 65 | rte_pdump_uninit(); 66 | #endif 67 | //rte_trace_save(); 68 | puts("Bye!"); 69 | exit(0); 70 | } 71 | } 72 | break; 73 | case PPPOE_PHASE: 74 | s_ppp_ccb->phase--; 75 | s_ppp_ccb->ppp_phase[0].state = S_INIT; 76 | s_ppp_ccb->ppp_phase[1].state = S_INIT; 77 | PPP_bye(s_ppp_ccb); 78 | break; 79 | case LCP_PHASE: 80 | s_ppp_ccb->ppp_processing = TRUE; 81 | s_ppp_ccb->cp = 0; 82 | s_ppp_ccb->ppp_phase[1].state = S_INIT; 83 | PPP_FSM(&(s_ppp_ccb->ppp), s_ppp_ccb, E_CLOSE); 84 | break; 85 | case DATA_PHASE: 86 | /* modify pppoe phase from DATA_PHASE to IPCP_PHASE */ 87 | s_ppp_ccb->phase--; 88 | case IPCP_PHASE: 89 | s_ppp_ccb->ppp_processing = TRUE; 90 | /* set ppp control protocol to IPCP */ 91 | s_ppp_ccb->cp = 1; 92 | PPP_FSM(&(s_ppp_ccb->ppp), s_ppp_ccb, E_CLOSE); 93 | break; 94 | default: 95 | ; 96 | } 97 | } 98 | 99 | /** 100 | * @brief pppd init function 101 | * @return int 102 | */ 103 | STATUS pppd_init(void *ccb) 104 | { 105 | vrg_ccb = (VRG_t *)ccb; 106 | 107 | vrg_ccb->ppp_ccb = mmap(NULL, sizeof(PPP_INFO_t)*vrg_ccb->user_count, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0); 108 | if (vrg_ccb->ppp_ccb == MAP_FAILED) { 109 | VRG_LOG(ERR, vrg_ccb->fp, NULL, PPPLOGMSG, "mmap ppp_ccb failed: %s", strerror(errno)); 110 | vrg_ccb->ppp_ccb = NULL; 111 | return ERROR; 112 | } 113 | 114 | srand(time(NULL)); 115 | 116 | PPP_INFO_t *ppp_ccb = vrg_ccb->ppp_ccb; 117 | ppp_interval = (uint32_t)(3*SECOND); 118 | 119 | for(int i=0; iuser_count; i++) { 120 | ppp_ccb[i].ppp_phase[0].state = S_INIT; 121 | ppp_ccb[i].ppp_phase[1].state = S_INIT; 122 | ppp_ccb[i].pppoe_phase.active = FALSE; 123 | /* subscriptor id starts from 1 */ 124 | ppp_ccb[i].user_num = i + 1; 125 | /* vlan of each subscriptor is adding the base_vlan value in vRG_setup file to i */ 126 | ppp_ccb[i].vlan = i + vrg_ccb->base_vlan; 127 | 128 | ppp_ccb[i].hsi_ipv4 = 0x0; 129 | ppp_ccb[i].hsi_ipv4_gw = 0x0; 130 | ppp_ccb[i].hsi_primary_dns = 0x0; 131 | ppp_ccb[i].hsi_second_dns = 0x0; 132 | ppp_ccb[i].phase = END_PHASE; 133 | ppp_ccb[i].is_pap_auth = FALSE; 134 | ppp_ccb[i].auth_method = CHAP_PROTOCOL; 135 | ppp_ccb[i].magic_num = rte_cpu_to_be_32((rand() % 0xFFFFFFFE) + 1); 136 | ppp_ccb[i].identifier = 0x0; 137 | for(int j=0; jfp; 143 | rte_timer_init(&(ppp_ccb[i].pppoe)); 144 | rte_timer_init(&(ppp_ccb[i].ppp)); 145 | rte_timer_init(&(ppp_ccb[i].nat)); 146 | rte_timer_init(&(ppp_ccb[i].ppp_alive)); 147 | rte_atomic16_init(&ppp_ccb[i].dp_start_bool); 148 | rte_atomic16_init(&ppp_ccb[i].ppp_bool); 149 | ppp_ccb[i].ppp_user_id = (unsigned char *)"asdf"; 150 | ppp_ccb[i].ppp_passwd = (unsigned char *)"zxcv"; 151 | ppp_ccb[i].pppoe_phase.pppoe_header_tag = vrg_malloc(pppoe_header_tag_t, RTE_CACHE_LINE_SIZE, RTE_CACHE_LINE_SIZE); 152 | if (ppp_ccb[i].pppoe_phase.pppoe_header_tag == NULL) { 153 | VRG_LOG(ERR, vrg_ccb->fp, NULL, PPPLOGMSG, "vrg_malloc failed: %s", rte_strerror(errno)); 154 | return ERROR; 155 | } 156 | } 157 | 158 | sleep(1); 159 | VRG_LOG(INFO, vrg_ccb->fp, NULL, PPPLOGMSG, "============ pppoe init successfully ==============\n"); 160 | return SUCCESS; 161 | } 162 | 163 | STATUS ppp_connect(PPP_INFO_t *ppp_ccb, U16 user_id) 164 | { 165 | if (ppp_ccb->phase > END_PHASE) { 166 | VRG_LOG(ERR, vrg_ccb->fp, ppp_ccb, PPPLOGMSG, "Error! User %u is in a pppoe connection", user_id); 167 | return ERROR; 168 | } 169 | ppp_ccb->phase = PPPOE_PHASE; 170 | ppp_ccb->pppoe_phase.max_retransmit = MAX_RETRAN; 171 | ppp_ccb->pppoe_phase.timer_counter = 0; 172 | if (send_pkt(ENCODE_PADI, ppp_ccb) == ERROR) 173 | PPP_bye(ppp_ccb); 174 | /* set ppp starting boolean flag to TRUE */ 175 | rte_atomic16_set(&ppp_ccb->ppp_bool, 1); 176 | rte_timer_reset(&ppp_ccb->pppoe, rte_get_timer_hz(), PERIODICAL, vrg_ccb->lcore.timer_thread, (rte_timer_cb_t)A_padi_timer_func, ppp_ccb); 177 | 178 | return SUCCESS; 179 | } 180 | 181 | STATUS ppp_disconnect(PPP_INFO_t *ppp_ccb, U16 user_id) 182 | { 183 | if (ppp_ccb->phase == END_PHASE) { 184 | VRG_LOG(ERR, vrg_ccb->fp, ppp_ccb, PPPLOGMSG, "Error! User %u is in init phase", user_id); 185 | return ERROR; 186 | } 187 | if (ppp_ccb->ppp_processing == TRUE) { 188 | VRG_LOG(ERR, vrg_ccb->fp, ppp_ccb, PPPLOGMSG, "Error! User %u is disconnecting pppoe connection, please wait...", user_id); 189 | return ERROR; 190 | } 191 | PPP_bye(ppp_ccb); 192 | 193 | return SUCCESS; 194 | } 195 | 196 | void exit_ppp(__attribute__((unused)) struct rte_timer *tim, PPP_INFO_t *ppp_ccb) 197 | { 198 | rte_atomic16_cmpset((U16 *)&(ppp_ccb->ppp_bool.cnt), 1, 0); 199 | rte_timer_stop(&(ppp_ccb->ppp)); 200 | rte_timer_stop(&(ppp_ccb->pppoe)); 201 | rte_timer_stop(&(ppp_ccb->ppp_alive)); 202 | if (ppp_ccb->phase > END_PHASE) 203 | vrg_ccb->cur_user--; 204 | ppp_ccb->phase = END_PHASE; 205 | ppp_ccb->ppp_phase[0].state = S_INIT; 206 | ppp_ccb->ppp_phase[1].state = S_INIT; 207 | ppp_ccb->pppoe_phase.active = FALSE; 208 | vrg_ccb->vrg_switch[ppp_ccb->user_num-1].is_hsi_enable = VRG_SUBMODULE_IS_TERMINATED; 209 | VRG_LOG(INFO, vrg_ccb->fp, ppp_ccb, PPPLOGMSG, "User %" PRIu16 " HSI module is terminated.\n", ppp_ccb->user_num); 210 | } 211 | 212 | /** 213 | * @brief PPPoE / PPP protocol processing 214 | * 215 | * @param mail 216 | * @retval SUCCESS if process successfully 217 | * @retval ERROR if process failed 218 | */ 219 | STATUS ppp_process(void *mail) 220 | { 221 | tVRG_MBX *vrg_mail = (tVRG_MBX *)mail; 222 | PPP_INFO_t *ppp_ccb = vrg_ccb->ppp_ccb; 223 | int ret; 224 | U16 event, user_id = 0; 225 | 226 | ret = get_session_id(vrg_mail, &user_id); 227 | if (ret == ERROR) 228 | return ERROR; 229 | 230 | ret = PPP_decode_frame(vrg_mail, &event ,&ppp_ccb[user_id]); 231 | if (ret == ERROR) 232 | return ERROR; 233 | 234 | if (check_auth_result(&ppp_ccb[user_id]) == 1) { 235 | return ERROR; 236 | } 237 | 238 | ppp_ccb[user_id].ppp_phase[ppp_ccb[user_id].cp].event = event; 239 | PPP_FSM(&(ppp_ccb[user_id].ppp), &ppp_ccb[user_id], event); 240 | vrg_mfree(ppp_ccb[user_id].ppp_phase[ppp_ccb[user_id].cp].ppp_options); 241 | 242 | return SUCCESS; 243 | } 244 | -------------------------------------------------------------------------------- /northbound/cmdline/cmds.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 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 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | 40 | #include "../grpc/vrg_grpc_client.h" 41 | 42 | #define PARSE_DELIMITER " \f\n\r\t\v" 43 | 44 | /**********************************************************/ 45 | 46 | struct cmd_info_result { 47 | cmdline_fixed_string_t info_token; 48 | cmdline_fixed_string_t subsystem; 49 | }; 50 | 51 | static void cmd_info_parsed(void *parsed_result, 52 | struct cmdline *cl, 53 | __attribute__((unused)) void *data) 54 | { 55 | struct cmd_info_result *res = parsed_result; 56 | 57 | if (strncmp(res->subsystem, "hsi", 3) == 0) 58 | vrg_grpc_get_hsi_info(); 59 | else if (strncmp(res->subsystem, "dhcp", 4) == 0) 60 | vrg_grpc_get_dhcp_info(); 61 | else if (strncmp(res->subsystem, "system", 6) == 0) 62 | vrg_grpc_get_system_info(); 63 | 64 | return; 65 | } 66 | 67 | cmdline_parse_token_string_t cmd_info_info_token = 68 | TOKEN_STRING_INITIALIZER(struct cmd_info_result, info_token, "show"); 69 | cmdline_parse_token_string_t cmd_show_subsystem = 70 | TOKEN_STRING_INITIALIZER(struct cmd_info_result, subsystem, "hsi#dhcp#system"); 71 | 72 | cmdline_parse_inst_t cmd_info = { 73 | .f = cmd_info_parsed, /* function to call */ 74 | .data = NULL, /* 2nd arg of func */ 75 | .help_str = "show user info, show ", 76 | .tokens = { /* token list, NULL terminated */ 77 | (void *)&cmd_info_info_token, 78 | (void *)&cmd_show_subsystem, 79 | NULL, 80 | }, 81 | }; 82 | 83 | /**********************************************************/ 84 | 85 | struct cmd_log_result { 86 | cmdline_fixed_string_t log_token; 87 | }; 88 | 89 | static void cmd_log_parsed(__attribute__((unused)) void *parsed_result, 90 | struct cmdline *cl, 91 | __attribute__((unused)) void *data) 92 | { 93 | #if 0 94 | char log_buf[256]; 95 | 96 | while (fgets(log_buf, 256, vrg_ccb->fp) != NULL) 97 | cmdline_printf(cl, "%s", log_buf); 98 | #endif 99 | cmdline_printf(cl, "\n"); 100 | } 101 | 102 | cmdline_parse_token_string_t cmd_log_log_token = 103 | TOKEN_STRING_INITIALIZER(struct cmd_log_result, log_token, "log"); 104 | 105 | cmdline_parse_inst_t cmd_log = { 106 | .f = cmd_log_parsed, /* function to call */ 107 | .data = NULL, /* 2nd arg of func */ 108 | .help_str = "show vRG log file", 109 | .tokens = { /* token list, NULL terminated */ 110 | (void *)&cmd_log_log_token, 111 | NULL, 112 | }, 113 | }; 114 | 115 | /**********************************************************/ 116 | 117 | struct cmd_quit_result { 118 | cmdline_fixed_string_t quit; 119 | }; 120 | 121 | static void cmd_quit_parsed(__attribute__((unused)) void *parsed_result, 122 | __attribute__((unused)) struct cmdline *cl, 123 | __attribute__((unused)) void *data) 124 | { 125 | cmdline_stdin_exit(cl); 126 | exit(0); 127 | } 128 | 129 | cmdline_parse_token_string_t cmd_quit_quit = 130 | TOKEN_STRING_INITIALIZER(struct cmd_quit_result, quit, "quit#exit"); 131 | 132 | cmdline_parse_inst_t cmd_quit = { 133 | .f = cmd_quit_parsed, /* function to call */ 134 | .data = NULL, /* 2nd arg of func */ 135 | .help_str = "close the application", 136 | .tokens = { /* token list, NULL terminated */ 137 | (void *)&cmd_quit_quit, 138 | NULL, 139 | }, 140 | }; 141 | 142 | /**********************************************************/ 143 | 144 | struct cmd_help_result { 145 | cmdline_fixed_string_t help; 146 | }; 147 | 148 | static void cmd_help_parsed(__attribute__((unused)) void *parsed_result, 149 | struct cmdline *cl, 150 | __attribute__((unused)) void *data) 151 | { 152 | cmdline_printf(cl,"usage: \n" 153 | "show to show information\n" 154 | "help to show usage commands\n" 155 | "disconnect [force] to disconnect session(s)\n" 156 | "connect to connect session(s)\n" 157 | "dhcp-server to start/stop dhcp server function\n" 158 | "quit/exit to quit vRG CLI\n"); 159 | } 160 | 161 | cmdline_parse_token_string_t cmd_help_help = 162 | TOKEN_STRING_INITIALIZER(struct cmd_help_result, help, "help"); 163 | 164 | cmdline_parse_inst_t cmd_help = { 165 | .f = cmd_help_parsed, /* function to call */ 166 | .data = NULL, /* 2nd arg of func */ 167 | .help_str = "show help", 168 | .tokens = { /* token list, NULL terminated */ 169 | (void *)&cmd_help_help, 170 | NULL, 171 | }, 172 | }; 173 | 174 | /**********************************************************/ 175 | 176 | struct cmd_connect_result { 177 | cmdline_fixed_string_t connect; 178 | cmdline_multi_string_t user_id_opt; 179 | }; 180 | 181 | static void cmd_connect_parsed(void *parsed_result, 182 | __attribute__((unused)) struct cmdline *cl, 183 | __attribute__((unused)) void *data) 184 | { 185 | struct cmd_connect_result *res = parsed_result; 186 | char *user_id_opt = res->user_id_opt; 187 | U8 user_id; 188 | 189 | char *user_id_str = strtok_r(user_id_opt, PARSE_DELIMITER, &user_id_opt); 190 | if (user_id_str == NULL) { 191 | cmdline_printf(cl, "user id input error\n"); 192 | return; 193 | } 194 | 195 | if (strcmp(user_id_str, "all") == 0) { 196 | user_id = 0; 197 | } else { 198 | user_id = strtoul(user_id_str, NULL, 10); 199 | if (user_id <= 0) { 200 | cmdline_printf(cl, "Wrong user id\n"); 201 | return; 202 | } 203 | } 204 | 205 | if (strcmp(res->connect, "connect") == 0) { 206 | vrg_grpc_hsi_connect(user_id); 207 | } else { 208 | char *is_force = strtok_r(user_id_opt, PARSE_DELIMITER, &user_id_opt); 209 | if (is_force == NULL) { 210 | vrg_grpc_hsi_disconnect(user_id, false); 211 | return; 212 | } 213 | if (strcmp(is_force, "force") != 0) { 214 | cmdline_printf(cl, "Wrong disconnect option\n"); 215 | return; 216 | } 217 | vrg_grpc_hsi_disconnect(user_id, true); 218 | } 219 | } 220 | 221 | cmdline_parse_token_string_t cmd_connect_connect = 222 | TOKEN_STRING_INITIALIZER(struct cmd_connect_result, connect, "connect#disconnect"); 223 | cmdline_parse_token_string_t cmd_connect_user_id_opt = 224 | TOKEN_STRING_INITIALIZER(struct cmd_connect_result, user_id_opt, TOKEN_STRING_MULTI); 225 | 226 | cmdline_parse_inst_t cmd_connect = { 227 | .f = cmd_connect_parsed, /* function to call */ 228 | .data = NULL, /* 2nd arg of func */ 229 | .help_str = "start/stop pppoe connection, " 230 | "connect|disconnect [force]", 231 | .tokens = { /* token list, NULL terminated */ 232 | (void *)&cmd_connect_connect, 233 | (void *)&cmd_connect_user_id_opt, 234 | NULL, 235 | }, 236 | }; 237 | 238 | /**********************************************************/ 239 | 240 | struct cmd_dhcp_result { 241 | cmdline_fixed_string_t dhcp; 242 | cmdline_fixed_string_t cmd; 243 | cmdline_fixed_string_t user_id; 244 | }; 245 | 246 | static void cmd_dhcp_parsed(void *parsed_result, 247 | __attribute__((unused)) struct cmdline *cl, 248 | __attribute__((unused)) void *data) 249 | { 250 | struct cmd_dhcp_result *res = parsed_result; 251 | U8 user_id; 252 | 253 | if (strcmp(res->user_id, "all") == 0) { 254 | user_id = 0; 255 | } else { 256 | user_id = strtoul(res->user_id, NULL, 10); 257 | if (user_id <= 0) { 258 | cmdline_printf(cl, "Wrong user id\n"); 259 | return; 260 | } 261 | } 262 | 263 | if (strcmp(res->cmd, "start") == 0) { 264 | vrg_grpc_dhcp_server_start(user_id); 265 | } else if (strcmp(res->cmd, "stop") == 0) { 266 | vrg_grpc_dhcp_server_stop(user_id); 267 | } else { 268 | cmdline_printf(cl, "Wrong dhcp cmd\n"); 269 | return; 270 | } 271 | } 272 | 273 | cmdline_parse_token_string_t cmd_dhcp_dhcp = 274 | TOKEN_STRING_INITIALIZER(struct cmd_dhcp_result, dhcp, "dhcp-server"); 275 | cmdline_parse_token_string_t cmd_dhcp_cmd = 276 | TOKEN_STRING_INITIALIZER(struct cmd_dhcp_result, cmd, "start#stop"); 277 | cmdline_parse_token_string_t cmd_dhcp_user_id = 278 | TOKEN_STRING_INITIALIZER(struct cmd_dhcp_result, user_id, NULL); 279 | 280 | cmdline_parse_inst_t cmd_dhcp = { 281 | .f = cmd_dhcp_parsed, /* function to call */ 282 | .data = NULL, /* 2nd arg of func */ 283 | .help_str = "start/stop dhcp server", 284 | .tokens = { /* token list, NULL terminated */ 285 | (void *)&cmd_dhcp_dhcp, 286 | (void *)&cmd_dhcp_cmd, 287 | (void *)&cmd_dhcp_user_id, 288 | NULL, 289 | }, 290 | }; 291 | 292 | /****** CONTEXT (list of instruction) */ 293 | cmdline_parse_ctx_t ctx[] = { 294 | (cmdline_parse_inst_t *)&cmd_info, 295 | (cmdline_parse_inst_t *)&cmd_quit, 296 | (cmdline_parse_inst_t *)&cmd_help, 297 | (cmdline_parse_inst_t *)&cmd_connect, 298 | (cmdline_parse_inst_t *)&cmd_dhcp, 299 | (cmdline_parse_inst_t *)&cmd_log, 300 | NULL, 301 | }; 302 | 303 | int main(int argc, char **argv) 304 | { 305 | grpc_init(); 306 | vrg_grpc_client_connect("unix:///var/run/vrg/vrg.sock"); 307 | //vrg_grpc_client_connect("127.0.0.1:50051"); 308 | 309 | struct cmdline *cl = cmdline_stdin_new(ctx, "vRG>"); 310 | if (cl == NULL) 311 | return -1; 312 | 313 | cmdline_interact(cl); 314 | 315 | cmdline_stdin_exit(cl); 316 | grpc_shutdown(); 317 | return 0; 318 | } 319 | -------------------------------------------------------------------------------- /northbound/grpc/vrg_grpc_client.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "vrg_node_grpc.h" 6 | #include "../../src/vrg.h" 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | using grpc::Channel; 13 | using grpc::ClientContext; 14 | using grpc::Status; 15 | using vrgnodeservice::VrgService; 16 | using vrgnodeservice::HsiRequest; 17 | using vrgnodeservice::HsiReply; 18 | 19 | class VRGNodeClient { 20 | public: 21 | VRGNodeClient(std::shared_ptr channel):stub_(VrgService::NewStub(channel)) {} 22 | std::unique_ptr stub_; 23 | }; 24 | 25 | std::unique_ptr vrg_client; 26 | 27 | void vrg_grpc_client_connect(char *server_address) { 28 | std::cout << "grpc client connecting to " << server_address << std::endl; 29 | auto channel = grpc::CreateChannel(server_address, grpc::InsecureChannelCredentials()); 30 | vrg_client = std::make_unique(channel); 31 | std::cout << "grpc client connected to " << server_address << std::endl; 32 | 33 | return; 34 | } 35 | 36 | void vrg_grpc_hsi_connect(U8 user_id) { 37 | std::cout << "grpc client hsi connect" << std::endl; 38 | HsiRequest request; 39 | HsiReply reply; 40 | request.set_user_id(user_id); 41 | ClientContext context; 42 | Status status = vrg_client->stub_->ConnectHsi(&context, request, &reply); 43 | if (status.ok()) { 44 | std::cout << "grpc client hsi connect ok" << std::endl; 45 | } else { 46 | std::cout << "grpc client hsi connect failed: " << std::endl; 47 | std::cout << " Error code: " << status.error_code() << std::endl; 48 | std::cout << " Error message: " << status.error_message() << std::endl; 49 | } 50 | return; 51 | } 52 | 53 | void vrg_grpc_hsi_disconnect(U8 user_id, bool force) { 54 | std::cout << "grpc client hsi disconnect" << std::endl; 55 | HsiRequest request; 56 | HsiReply reply; 57 | request.set_user_id(user_id); 58 | request.set_force(force); 59 | ClientContext context; 60 | Status status = vrg_client->stub_->DisconnectHsi(&context, request, &reply); 61 | if (status.ok()) { 62 | std::cout << "grpc client hsi disconnect ok" << std::endl; 63 | } else { 64 | std::cout << "grpc client hsi disconnect failed: " << std::endl; 65 | std::cout << " Error code: " << status.error_code() << std::endl; 66 | std::cout << " Error message: " << status.error_message() << std::endl; 67 | } 68 | return; 69 | } 70 | 71 | void vrg_grpc_dhcp_server_start(U8 user_id) { 72 | std::cout << "grpc client dhcp server start" << std::endl; 73 | DhcpServerRequest request; 74 | DhcpServerReply reply; 75 | request.set_user_id(user_id); 76 | ClientContext context; 77 | Status status = vrg_client->stub_->DhcpServerStart(&context, request, &reply); 78 | if (status.ok()) { 79 | std::cout << "grpc client dhcp server start ok" << std::endl; 80 | } else { 81 | std::cout << "grpc client dhcp server start failed: " << std::endl; 82 | std::cout << " Error code: " << status.error_code() << std::endl; 83 | std::cout << " Error message: " << status.error_message() << std::endl; 84 | } 85 | return; 86 | } 87 | 88 | void vrg_grpc_dhcp_server_stop(U8 user_id) { 89 | std::cout << "grpc client dhcp server stop" << std::endl; 90 | DhcpServerRequest request; 91 | DhcpServerReply reply; 92 | request.set_user_id(user_id); 93 | ClientContext context; 94 | Status status = vrg_client->stub_->DhcpServerStop(&context, request, &reply); 95 | if (status.ok()) { 96 | std::cout << "grpc client dhcp server stop ok" << std::endl; 97 | } else { 98 | std::cout << "grpc client dhcp server stop failed: " << std::endl; 99 | std::cout << " Error code: " << status.error_code() << std::endl; 100 | std::cout << " Error message: " << status.error_message() << std::endl; 101 | } 102 | return; 103 | } 104 | 105 | void vrg_grpc_get_system_info() { 106 | std::cout << "grpc client getting vRG system and node info" << std::endl; 107 | google::protobuf::Empty request; 108 | VrgSystemInfo reply_vrg_system; 109 | NodeStatus reply_node_status; 110 | ClientContext context_vrg_system, context_node_status; 111 | Status status = vrg_client->stub_->GetVrgSystemInfo(&context_vrg_system, request, &reply_vrg_system); 112 | if (status.ok()) { 113 | std::cout << "grpc client get vRG system info ok" << std::endl; 114 | std::cout << " vRG version: " << reply_vrg_system.base_info().vrg_version() << std::endl; 115 | std::cout << " Build date: " << reply_vrg_system.base_info().build_date() << std::endl; 116 | std::cout << " DPDK version: " << reply_vrg_system.base_info().dpdk_version() << std::endl; 117 | std::cout << " DPDK EAL args: " << reply_vrg_system.base_info().dpdk_eal_args() << std::endl; 118 | std::cout << " Number of subscribers: " << reply_vrg_system.base_info().num_users() << std::endl; 119 | 120 | std::cout << " NICs: " << std::endl; 121 | for(int i=0; i(mac_bin.data()); 129 | for(size_t j=0; jstub_->GetNodeStatus(&context_node_status, request, &reply_node_status); 148 | if (status.ok()) { 149 | std::cout << "grpc client get node status ok" << std::endl; 150 | std::cout << " Node OS version: " << reply_node_status.node_os_version() << std::endl; 151 | std::cout << " Node uptime (seconds): " << reply_node_status.node_uptime() << std::endl; 152 | std::cout << " Node IP address: " << reply_node_status.node_ip_info() << std::endl; 153 | std::cout << " Health status: " << (reply_node_status.healthy() ? "Healthy" : "Unhealthy") << std::endl; 154 | 155 | } else { 156 | std::cout << "grpc client get node status failed: " << std::endl; 157 | std::cout << " Error code: " << status.error_code() << std::endl; 158 | std::cout << " Error message: " << status.error_message() << std::endl; 159 | } 160 | } 161 | 162 | void vrg_grpc_get_hsi_info() { 163 | std::cout << "grpc client getting hsi info" << std::endl; 164 | google::protobuf::Empty request; 165 | VrgHsiInfo reply; 166 | ClientContext context; 167 | Status status = vrg_client->stub_->GetVrgHsiInfo(&context, request, &reply); 168 | if (status.ok()) { 169 | std::cout << "grpc client get hsi info ok" << std::endl; 170 | for(int i=0; istub_->GetVrgDhcpInfo(&context, request, &reply); 202 | if (status.ok()) { 203 | std::cout << "grpc client get dhcp info ok" << std::endl; 204 | for(int i=0; i 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include "vrg.h" 24 | #include "pppd/fsm.h" 25 | #include "dp.h" 26 | #include "dbg.h" 27 | #include "init.h" 28 | #include "dp_flow.h" 29 | #include "dhcpd/dhcpd.h" 30 | #include "config.h" 31 | #include "timer.h" 32 | #include "utils.h" 33 | 34 | #include "../northbound/grpc/vrg_grpc_server.h" 35 | 36 | #define BURST_SIZE 32 37 | 38 | rte_atomic16_t cp_recv_cums; 39 | VRG_t vrg_ccb; 40 | 41 | void link_disconnnect(struct rte_timer *tim, VRG_t *vrg_ccb) 42 | { 43 | for(int i=0; iuser_count; i++) 44 | exit_ppp(tim, &vrg_ccb->ppp_ccb[i]); 45 | } 46 | 47 | void vrg_force_terminate_hsi(VRG_t *vrg_ccb) 48 | { 49 | /* force terminate hsi does not mean quit vRG */ 50 | //vrg_ccb->quit_flag = TRUE; 51 | for(int j=0; juser_count; j++) { 52 | if (vrg_ccb->ppp_ccb[j].phase == END_PHASE) 53 | vrg_ccb->cur_user++; 54 | PPP_bye(&(vrg_ccb->ppp_ccb[j])); 55 | } 56 | } 57 | 58 | void *vrg_loop_check_feature(void *arg) 59 | { 60 | VRG_t *vrg_ccb = (VRG_t *)arg; 61 | 62 | for(;;) { 63 | for(int i=0; iuser_count; i++) { 64 | if (vrg_ccb->vrg_switch[i].is_hsi_enable == VRG_SUBMODULE_IS_ENABLED) { 65 | VRG_LOG(INFO, vrg_ccb->fp, NULL, NULL, "User %d pppoe is spawning\n", i+1); 66 | if (ppp_connect(&(vrg_ccb->ppp_ccb[i]), i+1) == SUCCESS) 67 | vrg_ccb->cur_user++; 68 | vrg_ccb->vrg_switch[i].is_hsi_enable = VRG_SUBMODULE_IS_SPAWNING; 69 | } else if (vrg_ccb->vrg_switch[i].is_hsi_enable == VRG_SUBMODULE_IS_DISABLED) { 70 | VRG_LOG(INFO, vrg_ccb->fp, NULL, NULL, "User %d pppoe is terminating\n", i+1); 71 | if (ppp_disconnect(&(vrg_ccb->ppp_ccb[i]), i+1) == SUCCESS) 72 | vrg_ccb->cur_user++; 73 | vrg_ccb->vrg_switch[i].is_hsi_enable = VRG_SUBMODULE_IS_TERMINATING; 74 | } else if (vrg_ccb->vrg_switch[i].is_hsi_enable == VRG_SUBMODULE_IS_FORCE_DISABLED) { 75 | VRG_LOG(INFO, vrg_ccb->fp, NULL, NULL, "User %d pppoe is force terminating\n", i+1); 76 | vrg_force_terminate_hsi(vrg_ccb); 77 | vrg_ccb->vrg_switch[i].is_hsi_enable = VRG_SUBMODULE_IS_TERMINATING; 78 | } 79 | 80 | if (vrg_ccb->vrg_switch[i].is_dhcp_server_enable == VRG_SUBMODULE_IS_ENABLED) { 81 | vrg_ccb->vrg_switch[i].is_dhcp_server_enable = VRG_SUBMODULE_IS_SPAWNING; 82 | VRG_LOG(INFO, vrg_ccb->fp, NULL, NULL, "User %d dhcp server is spawning\n", i+1); 83 | if (rte_atomic16_read(&vrg_ccb->dhcp_ccb[i].dhcp_bool) == 1) { 84 | VRG_LOG(ERR, vrg_ccb->fp, &(vrg_ccb->dhcp_ccb[i]), DHCPLOGMSG, "Error! User %u dhcp server is already on", i+1); 85 | break; 86 | } 87 | rte_atomic16_set(&vrg_ccb->dhcp_ccb[i].dhcp_bool, 1); 88 | vrg_ccb->vrg_switch[i].is_dhcp_server_enable = VRG_SUBMODULE_IS_SPAWNED; 89 | VRG_LOG(INFO, vrg_ccb->fp, &(vrg_ccb->dhcp_ccb[i]), DHCPLOGMSG, "User %d dhcp server is spawned\n", i+1); 90 | } else if (vrg_ccb->vrg_switch[i].is_dhcp_server_enable == VRG_SUBMODULE_IS_DISABLED) { 91 | vrg_ccb->vrg_switch[i].is_dhcp_server_enable = VRG_SUBMODULE_IS_TERMINATING; 92 | VRG_LOG(INFO, vrg_ccb->fp, NULL, NULL, "User %d dhcp server is terminating\n", i+1); 93 | if (rte_atomic16_read(&vrg_ccb->dhcp_ccb[i].dhcp_bool) == 0) { 94 | VRG_LOG(ERR, vrg_ccb->fp, &(vrg_ccb->dhcp_ccb[i]), DHCPLOGMSG, "Error! User %u dhcp server is already off", i+1); 95 | break; 96 | } 97 | rte_atomic16_set(&vrg_ccb->dhcp_ccb[i].dhcp_bool, 0); 98 | vrg_ccb->vrg_switch[i].is_dhcp_server_enable = VRG_SUBMODULE_IS_TERMINATED; 99 | VRG_LOG(INFO, vrg_ccb->fp, &(vrg_ccb->dhcp_ccb[i]), DHCPLOGMSG, "User %d dhcp server is terminated\n", i+1); 100 | } 101 | } 102 | } 103 | 104 | pthread_exit(NULL); 105 | } 106 | 107 | /*************************************************************** 108 | * vrg_loop : 109 | * 110 | * purpose: Main event loop. 111 | ***************************************************************/ 112 | int vrg_loop(VRG_t *vrg_ccb) 113 | { 114 | tVRG_MBX *mail[RING_BURST_SIZE]; 115 | U16 burst_size; 116 | U16 recv_type; 117 | 118 | for(;;) { 119 | burst_size = vrg_ring_dequeue(rte_ring, (void **)mail); 120 | /* update the ring queue index between hsi_recvd() */ 121 | rte_atomic16_add(&cp_recv_cums,burst_size); 122 | if (rte_atomic16_read(&cp_recv_cums) > 32) 123 | rte_atomic16_sub(&cp_recv_cums,32); 124 | for(int i=0; irefp[1]) == 1) { 138 | if (mail[i]->refp[0] == LINK_DOWN) 139 | rte_timer_reset(&vrg_ccb->link, 10*rte_get_timer_hz(), SINGLE, vrg_ccb->lcore.timer_thread, (rte_timer_cb_t)link_disconnnect, &vrg_ccb); 140 | else if (mail[i]->refp[0] == LINK_UP) 141 | rte_timer_stop(&vrg_ccb->link); 142 | } 143 | vrg_mfree(mail[i]); 144 | break; 145 | default: 146 | ; 147 | } 148 | mail[i] = NULL; 149 | } 150 | } 151 | return ERROR; 152 | } 153 | 154 | int control_plane(VRG_t *vrg_ccb) 155 | { 156 | if (vrg_loop(vrg_ccb) == ERROR) 157 | return -1; 158 | return 0; 159 | } 160 | 161 | int vrg_submodule_checker(VRG_t *vrg_ccb) 162 | { 163 | pthread_t thread_id; 164 | pthread_attr_t thread_attr; 165 | int ret; 166 | 167 | ret = pthread_attr_init(&thread_attr); 168 | if (ret != 0) { 169 | VRG_LOG(ERR, vrg_ccb->fp, NULL, NULL, "Error: pthread_attr_init failed: %s\n", strerror(ret)); 170 | return -1; 171 | } 172 | 173 | cpu_set_t cpuset; 174 | CPU_ZERO(&cpuset); 175 | CPU_SET(0, &cpuset); 176 | 177 | ret = pthread_attr_setaffinity_np(&thread_attr, sizeof(cpu_set_t), &cpuset); 178 | if (ret != 0) 179 | VRG_LOG(WARN, vrg_ccb->fp, NULL, NULL, "pthread_attr_setaffinity_np failed: %s\n", strerror(ret)); 180 | 181 | ret = pthread_create(&thread_id, &thread_attr, vrg_loop_check_feature, (void *)vrg_ccb); 182 | if (ret != 0) { 183 | VRG_LOG(ERR, vrg_ccb->fp, NULL, NULL, "pthread_create failed: %s\n", strerror(ret)); 184 | pthread_attr_destroy(&thread_attr); 185 | return -1; 186 | } 187 | ret = pthread_setname_np(thread_id, "vrg_check"); 188 | if (ret != 0) { 189 | VRG_LOG(WARN, vrg_ccb->fp, NULL, NULL, "pthread_setname_np failed: %s\n", strerror(ret)); 190 | } else { 191 | VRG_LOG(INFO, vrg_ccb->fp, NULL, NULL, "Successfully named the thread 'vrg_check'\n"); 192 | } 193 | 194 | pthread_attr_destroy(&thread_attr); 195 | 196 | return 0; 197 | } 198 | 199 | int northbound(VRG_t *vrg_ccb) 200 | { 201 | unlink(vrg_ccb->unix_sock_path); 202 | vrg_grpc_server_run(vrg_ccb); 203 | 204 | return 0; 205 | } 206 | 207 | int vrg_start(int argc, char **argv) 208 | { 209 | grpc_init(); 210 | vrg_ccb.eal_args = make_eal_args_string(argc, (const char **)argv); 211 | int ret = rte_eal_init(argc, argv); 212 | if (ret < 0) 213 | rte_exit(EXIT_FAILURE, "rte initlize fail.\n"); 214 | 215 | if (rte_lcore_count() < 8) 216 | rte_exit(EXIT_FAILURE, "We need at least 8 cores.\n"); 217 | if (rte_eth_dev_count_avail() < 2) 218 | rte_exit(EXIT_FAILURE, "We need at least 2 eth ports.\n"); 219 | 220 | get_all_lcore_id(&vrg_ccb.lcore); 221 | 222 | if (rte_eth_dev_socket_id(0) > 0 && rte_eth_dev_socket_id(0) != (int)rte_lcore_to_socket_id(vrg_ccb.lcore.lan_thread)) 223 | printf("WARNING, LAN port is on remote NUMA node to polling thread.\n\tPerformance will not be optimal.\n"); 224 | if (rte_eth_dev_socket_id(1) > 0 && rte_eth_dev_socket_id(1) != (int)rte_lcore_to_socket_id(vrg_ccb.lcore.wan_thread)) 225 | printf("WARNING, WAN port is on remote NUMA node to polling thread.\n\tPerformance will not be optimal.\n"); 226 | 227 | dbg_init((void *)&vrg_ccb); 228 | /* Read network config */ 229 | struct vrg_config vrg_cfg; 230 | if (parse_config("/etc/vrg/config.cfg", &vrg_ccb, &vrg_cfg) != SUCCESS) { 231 | printf("parse config file error\n"); 232 | return -1; 233 | } 234 | VRG_LOG(INFO, vrg_ccb.fp, NULL, NULL, "vRG log level is %s", loglvl2str(vrg_ccb.loglvl)); 235 | if (vrg_ccb.non_vlan_mode != FALSE) { 236 | vrg_ccb.user_count = 1; 237 | vrg_ccb.base_vlan = 2; 238 | } 239 | vrg_ccb.unix_sock_path = vrg_cfg.unix_sock_path; 240 | vrg_ccb.node_grpc_ip_port = vrg_cfg.node_grpc_ip_port; 241 | vrg_ccb.fp = fopen(vrg_cfg.log_path, "w+"); 242 | if (vrg_ccb.fp) 243 | rte_openlog_stream(vrg_ccb.fp); 244 | 245 | if (vrg_ccb.user_count < 1 || vrg_ccb.base_vlan < 2) 246 | rte_exit(EXIT_FAILURE, "vRG system configuration failed.\n"); 247 | if (vrg_ccb.base_vlan + vrg_ccb.user_count > 4094) 248 | rte_exit(EXIT_FAILURE, "vRG system configure too many users.\n"); 249 | 250 | /*vrg_ccb.ppp_ccb_mp = rte_mempool_create("vrg_ccb.ppp_ccb", 4095, sizeof(PPP_INFO_t), RTE_MEMPOOL_CACHE_MAX_SIZE, 0, NULL, NULL, NULL, NULL, rte_socket_id(), 0); 251 | if (vrg_ccb.ppp_ccb_mp == NULL) 252 | rte_exit(EXIT_FAILURE, "vRG system mempool init failed: %s\n", rte_strerror(errno)); 253 | 254 | if (rte_mempool_get_bulk(vrg_ccb.ppp_ccb_mp, (void **)&vrg_ccb.ppp_ccb, user_count) < 0) 255 | rte_exit(EXIT_FAILURE, "vRG system memory allocate from mempool failed: %s\n", rte_strerror(errno));*/ 256 | //vrg_ccb.ppp_ccb = te_malloc(NULL, user_count*sizeof(PPP_INFO_t), 0); 257 | //if (!vrg_ccb.ppp_ccb) 258 | //rte_exit(EXIT_FAILURE, "vRG system malloc from hugepage failed.\n"); 259 | /* init users and ports info */ 260 | 261 | ret = sys_init(&vrg_ccb); 262 | if (ret) { 263 | VRG_LOG(ERR, vrg_ccb.fp, NULL, NULL, "System initiation failed: %s", rte_strerror(ret)); 264 | goto err; 265 | } 266 | 267 | rte_atomic16_init(&cp_recv_cums); 268 | 269 | if (pppd_init((void *)&vrg_ccb) == ERROR) { 270 | VRG_LOG(ERR, vrg_ccb.fp, NULL, NULL, "PPP initiation failed"); 271 | goto err; 272 | } 273 | codec_init((void *)&vrg_ccb); 274 | dhcp_init((void *)&vrg_ccb); 275 | fsm_init((void *)&vrg_ccb); 276 | /* Init the pppoe alive user count */ 277 | vrg_ccb.cur_user = 0; 278 | vrg_ccb.quit_flag = FALSE; 279 | rte_prefetch2(&vrg_ccb); 280 | #ifdef RTE_LIBRTE_PDUMP 281 | /* initialize packet capture framework */ 282 | rte_pdump_init(); 283 | #endif 284 | #if 0 285 | struct rte_flow_error error; 286 | struct rte_flow *flow = generate_flow(0, 1, &error); 287 | if (!flow) { 288 | printf("Flow can't be created %d message: %s\n", error.type, error.message ? error.message : "(no stated reason)"); 289 | rte_exit(EXIT_FAILURE, "error in creating flow"); 290 | } 291 | #endif 292 | rte_eal_remote_launch((lcore_function_t *)control_plane, (void *)&vrg_ccb, vrg_ccb.lcore.ctrl_thread); 293 | rte_eal_remote_launch((lcore_function_t *)wan_recvd, (void *)&vrg_ccb, vrg_ccb.lcore.wan_thread); 294 | rte_eal_remote_launch((lcore_function_t *)downlink, (void *)&vrg_ccb, vrg_ccb.lcore.down_thread); 295 | rte_eal_remote_launch((lcore_function_t *)lan_recvd, (void *)&vrg_ccb, vrg_ccb.lcore.lan_thread); 296 | rte_eal_remote_launch((lcore_function_t *)uplink, (void *)&vrg_ccb, vrg_ccb.lcore.up_thread); 297 | rte_eal_remote_launch((lcore_function_t *)gateway, (void *)&vrg_ccb, vrg_ccb.lcore.gateway_thread); 298 | rte_eal_remote_launch((lcore_function_t *)timer_loop, (void *)&vrg_ccb, vrg_ccb.lcore.timer_thread); 299 | 300 | if (vrg_submodule_checker(&vrg_ccb) == -1) { 301 | VRG_LOG(ERR, vrg_ccb.fp, NULL, NULL, "vRG submodule check thread create failed"); 302 | goto err; 303 | } 304 | 305 | northbound(&vrg_ccb); 306 | rte_eal_mp_wait_lcore(); 307 | 308 | free(vrg_ccb.eal_args); 309 | 310 | return 0; 311 | 312 | err: 313 | return -1; 314 | } 315 | 316 | /*--------------------------------------------------------- 317 | * vrg_int : signal handler for INTR-C only 318 | *--------------------------------------------------------*/ 319 | void vrg_interrupt() 320 | { 321 | VRG_LOG(INFO, vrg_ccb.fp, NULL, NULL, "vRG system interupt!"); 322 | rte_ring_free(rte_ring); 323 | rte_ring_free(uplink_q); 324 | rte_ring_free(downlink_q); 325 | rte_ring_free(gateway_q); 326 | fclose(vrg_ccb.fp); 327 | VRG_LOG(INFO, vrg_ccb.fp, NULL, NULL, "bye!"); 328 | grpc_shutdown(); 329 | exit(0); 330 | } 331 | -------------------------------------------------------------------------------- /src/dp_codec.h: -------------------------------------------------------------------------------- 1 | /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ 2 | DP_CODEC.H 3 | 4 | Designed by THE on JAN 21, 2021 5 | /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/ 6 | 7 | #ifndef _DP_CODEC_H_ 8 | #define _DP_CODEC_H_ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "protocol.h" 17 | #include "init.h" 18 | #include "dp_codec.h" 19 | 20 | enum { 21 | gen_port_q = 0, 22 | up_port_q, 23 | down_port_q, 24 | ctrl_port_q, 25 | }; 26 | 27 | static inline void build_icmp_unreach(VRG_t *vrg_ccb, struct rte_mbuf *pkt, U16 user_index, struct rte_ether_hdr *eth_hdr, vlan_header_t old_vlan_hdr, struct rte_ipv4_hdr *ip_hdr) 28 | { 29 | vlan_header_t *vlan_header; 30 | 31 | struct rte_ether_hdr *new_eth_hdr = rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *); 32 | rte_ether_addr_copy(ð_hdr->src_addr, &new_eth_hdr->dst_addr); 33 | rte_ether_addr_copy(&vrg_ccb->nic_info.hsi_lan_mac, &new_eth_hdr->src_addr); 34 | new_eth_hdr->ether_type = rte_cpu_to_be_16(VLAN); 35 | vlan_header = (vlan_header_t *)(new_eth_hdr + 1); 36 | *vlan_header = old_vlan_hdr; 37 | struct rte_ipv4_hdr *new_ip_hdr = (struct rte_ipv4_hdr *)(vlan_header + 1); 38 | *new_ip_hdr = *ip_hdr; 39 | new_ip_hdr->dst_addr = ip_hdr->src_addr; 40 | new_ip_hdr->src_addr = vrg_ccb->lan_ip; 41 | new_ip_hdr->packet_id = 0; 42 | new_ip_hdr->next_proto_id = IPPROTO_ICMP; 43 | struct rte_icmp_hdr *icmp_hdr = (struct rte_icmp_hdr *)(new_ip_hdr + 1); 44 | icmp_hdr->icmp_type = ICMP_UNREACHABLE; 45 | icmp_hdr->icmp_code = ICMP_FRAG_NEED_DF_SET; 46 | icmp_hdr->icmp_ident = 0; //unsed field 47 | icmp_hdr->icmp_seq_nb = rte_cpu_to_be_16(ETH_MTU - sizeof(struct rte_ipv4_hdr) - sizeof(vlan_header_t) - sizeof(pppoe_header_t) - sizeof(ppp_payload_t)); // MTU size is mentioned here 48 | rte_memcpy((char *)(icmp_hdr + 1), (char *)ip_hdr, sizeof(struct rte_ipv4_hdr) + 8); 49 | new_ip_hdr->total_length = rte_cpu_to_be_16(sizeof(struct rte_ipv4_hdr) + sizeof(struct rte_icmp_hdr) + sizeof(struct rte_ipv4_hdr) + 8); 50 | icmp_hdr->icmp_cksum = 0; 51 | rte_wmb(); 52 | icmp_hdr->icmp_cksum = (U16)~rte_raw_cksum((const void *)icmp_hdr, sizeof(struct rte_icmp_hdr) + sizeof(struct rte_ipv4_hdr) + 8); 53 | new_ip_hdr->hdr_checksum = 0; 54 | new_ip_hdr->hdr_checksum = rte_ipv4_cksum(new_ip_hdr); 55 | pkt->pkt_len = pkt->data_len = rte_be_to_cpu_16(new_ip_hdr->total_length) + sizeof(struct rte_ether_hdr) + sizeof(vlan_header_t); 56 | //pkt->ol_flags |= PKT_TX_IPV4 | PKT_TX_IP_CKSUM; 57 | //pkt->l2_len = sizeof(struct rte_ether_hdr) + sizeof(vlan_header_t); 58 | } 59 | 60 | static int encaps_udp(VRG_t *vrg_ccb, struct rte_mbuf **single_pkt, struct rte_ether_hdr *eth_hdr, vlan_header_t *vlan_header, struct rte_ipv4_hdr *ip_hdr, U16 user_index) 61 | { 62 | struct rte_udp_hdr *udphdr; 63 | U32 new_port_id; 64 | pppoe_header_t *pppoe_header; 65 | vlan_header_t old_vlan_hdr; 66 | int32_t new_pkt_num = 0; 67 | 68 | old_vlan_hdr = *vlan_header; 69 | if (unlikely((*single_pkt)->pkt_len > (ETH_MTU - (U16)(sizeof(vlan_header_t) + sizeof(pppoe_header_t) + sizeof(ppp_payload_t))))) { 70 | struct rte_mbuf *pkt = rte_pktmbuf_alloc(direct_pool[0]); 71 | build_icmp_unreach(vrg_ccb, pkt, user_index, eth_hdr, old_vlan_hdr, ip_hdr); 72 | if (unlikely(vrg_ccb->non_vlan_mode == TRUE)) 73 | rte_vlan_strip(pkt); 74 | rte_eth_tx_burst(0, gen_port_q, &pkt, 1); 75 | rte_pktmbuf_free((*single_pkt)); 76 | new_pkt_num = 0; 77 | } 78 | else { 79 | new_pkt_num = 1; 80 | ip_hdr->hdr_checksum = 0; 81 | 82 | /* for nat */ 83 | //(*single_pkt)->ol_flags |= PKT_TX_IPV4 | PKT_TX_IP_CKSUM | PKT_TX_UDP_CKSUM; 84 | 85 | udphdr = (struct rte_udp_hdr *)(ip_hdr + 1); 86 | nat_udp_learning(eth_hdr,ip_hdr,udphdr,&new_port_id,vrg_ccb->ppp_ccb[user_index].addr_table); 87 | ip_hdr->src_addr = vrg_ccb->ppp_ccb[user_index].hsi_ipv4; 88 | udphdr->src_port = rte_cpu_to_be_16(new_port_id); 89 | rte_atomic16_set(&vrg_ccb->ppp_ccb[user_index].addr_table[new_port_id].is_alive, 10); 90 | ip_hdr->hdr_checksum = rte_ipv4_cksum(ip_hdr); 91 | udphdr->dgram_cksum = 0; 92 | udphdr->dgram_cksum = rte_ipv4_udptcp_cksum(ip_hdr,udphdr); 93 | 94 | /* for PPPoE */ 95 | eth_hdr = (struct rte_ether_hdr *)rte_pktmbuf_prepend((*single_pkt), (U16)(sizeof(struct rte_ether_hdr) + sizeof(vlan_header_t) + sizeof(pppoe_header_t) + sizeof(ppp_payload_t))); 96 | rte_ether_addr_copy(&vrg_ccb->nic_info.hsi_wan_src_mac, ð_hdr->src_addr); 97 | rte_ether_addr_copy(&vrg_ccb->ppp_ccb[user_index].PPP_dst_mac, ð_hdr->dst_addr); 98 | eth_hdr->ether_type = rte_cpu_to_be_16(VLAN); 99 | vlan_header = (vlan_header_t *)(eth_hdr + 1); 100 | vlan_header->tci_union.tci_value = old_vlan_hdr.tci_union.tci_value; 101 | vlan_header->next_proto = rte_cpu_to_be_16(ETH_P_PPP_SES); 102 | 103 | pppoe_header = (pppoe_header_t *)(vlan_header + 1); 104 | pppoe_header->ver_type = VER_TYPE; 105 | pppoe_header->code = 0; 106 | pppoe_header->session_id = vrg_ccb->ppp_ccb[user_index].session_id; 107 | pppoe_header->length = rte_cpu_to_be_16(((*single_pkt)->data_len) - (U16)(sizeof(struct rte_ether_hdr) + sizeof(vlan_header_t) + sizeof(pppoe_header_t))); 108 | *(U16 *)(pppoe_header + 1) = rte_cpu_to_be_16(PPP_IP_PROTOCOL); 109 | } 110 | 111 | return new_pkt_num; 112 | } 113 | 114 | static int encaps_tcp(VRG_t *vrg_ccb, struct rte_mbuf **single_pkt, struct rte_ether_hdr *eth_hdr, vlan_header_t *vlan_header, struct rte_ipv4_hdr *ip_hdr, U16 user_index) 115 | { 116 | struct rte_tcp_hdr *tcphdr; 117 | U32 new_port_id; 118 | pppoe_header_t *pppoe_header; 119 | vlan_header_t old_vlan_hdr; 120 | int32_t new_pkt_num = 0; 121 | 122 | old_vlan_hdr = *vlan_header; 123 | /* for nat */ 124 | //(*single_pkt)->ol_flags |= PKT_TX_IPV4 | PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM; 125 | //struct rte_mbuf *new_pkt; 126 | if (unlikely((*single_pkt)->pkt_len > (ETH_MTU - (U16)(sizeof(vlan_header_t) + sizeof(pppoe_header_t) + sizeof(ppp_payload_t))))) { 127 | #if 0 //for re-fragmentation, needed to implementation in the future 128 | ip_hdr->hdr_checksum = 0; 129 | tcphdr = (struct rte_tcp_hdr *)(ip_hdr + 1); 130 | nat_tcp_learning(eth_hdr,ip_hdr,tcphdr,&new_port_id,vrg_ccb.ppp_ccb[user_index].addr_table); 131 | ori_src_ip = ip_hdr->src_addr; 132 | ip_hdr->src_addr = vrg_ccb.ppp_ccb[user_index].ipv4; 133 | tcphdr->src_port = rte_cpu_to_be_16(new_port_id); 134 | vrg_ccb.ppp_ccb[user_index].addr_table[new_port_id].is_alive = 10; 135 | ip_hdr->hdr_checksum = rte_ipv4_cksum(ip_hdr); 136 | tcphdr->cksum = 0; 137 | tcphdr->cksum = rte_ipv4_udptcp_cksum(ip_hdr,tcphdr); 138 | 139 | ip_hdr->fragment_offset = 0; 140 | //printf("pkt len = %u, data len = %u\n", (*single_pkt)->pkt_len, (*single_pkt)->data_len); 141 | new_pkt_num = rte_ipv4_fragment_packet((*single_pkt), &new_pkt, 6, IPV4_MTU_DEFAULT - sizeof(vlan_header_t) - sizeof(pppoe_header_t) - sizeof(ppp_payload_t), direct_pool[0], indirect_pool[0]); 142 | rte_pktmbuf_free((*single_pkt)); 143 | if (unlikely(new_pkt_num < 0)) { 144 | printf("pkt fragmentation error: %s\n", rte_strerror(new_pkt_num)); 145 | return -1; 146 | } 147 | 148 | for ((*single_pkt)=new_pkt; (*single_pkt)!=NULL; (*single_pkt)=(*single_pkt)->next) { 149 | ip_hdr = (struct rte_ipv4_hdr *)(rte_pktmbuf_mtod((*single_pkt),unsigned char *)); 150 | tcphdr = (struct rte_tcp_hdr *)(ip_hdr + 1); 151 | struct rte_ether_hdr *eth_hdr = (struct rte_ether_hdr *)rte_pktmbuf_prepend((*single_pkt), (U16)(sizeof(struct rte_ether_hdr) + sizeof(vlan_header_t) + sizeof(pppoe_header_t) + sizeof(ppp_payload_t))); 152 | if (eth_hdr == NULL) { 153 | rte_panic("No headroom in mbuf.\n"); 154 | } 155 | 156 | //(*single_pkt)->ol_flags = PKT_TX_IPV4 | PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM; 157 | (*single_pkt)->l2_len = sizeof(struct rte_ether_hdr) + sizeof(vlan_header_t) + sizeof(pppoe_header_t) + sizeof(ppp_payload_t); 158 | 159 | rte_memcpy(eth_hdr->src_addr.addr_bytes,vrg_ccb.ppp_ccb[user_index].src_mac,ETH_ALEN); 160 | rte_memcpy(eth_hdr->dst_addr.addr_bytes,vrg_ccb.ppp_ccb[user_index].dst_mac,ETH_ALEN); 161 | 162 | //rte_ether_addr_copy(&vrg_ccb.ppp_ccb[user_index].src_mac, ð_hdr->src_addr); 163 | //rte_ether_addr_copy(&vrg_ccb.ppp_ccb[user_index].dst_mac, ð_hdr->dst_addr); 164 | eth_hdr->ether_type = rte_cpu_to_be_16(VLAN); 165 | vlan_header = (vlan_header_t *)(eth_hdr + 1); 166 | vlan_header->tci_union.tci_value = old_vlan_hdr.tci_union.tci_value; 167 | vlan_header->next_proto = rte_cpu_to_be_16(ETH_P_PPP_SES); 168 | pppoe_header = (pppoe_header_t *)(vlan_header + 1); 169 | pppoe_header->ver_type = VER_TYPE; 170 | pppoe_header->code = 0; 171 | pppoe_header->session_id = vrg_ccb.ppp_ccb[user_index].session_id; 172 | pppoe_header->length = rte_cpu_to_be_16(((*single_pkt)->data_len) - (U16)(sizeof(struct rte_ether_hdr) + sizeof(vlan_header_t) + sizeof(pppoe_header_t))); 173 | *(U16 *)(pppoe_header + 1) = rte_cpu_to_be_16(PPP_IP_PROTOCOL); 174 | ip_hdr->hdr_checksum = rte_ipv4_cksum(ip_hdr); 175 | tcphdr->cksum = rte_ipv4_udptcp_cksum(ip_hdr,tcphdr); 176 | } 177 | (*single_pkt) = new_pkt; 178 | #else 179 | struct rte_mbuf *pkt = rte_pktmbuf_alloc(direct_pool[0]); 180 | build_icmp_unreach(vrg_ccb, pkt, user_index, eth_hdr, old_vlan_hdr, ip_hdr); 181 | if (unlikely(vrg_ccb->non_vlan_mode == TRUE)) 182 | rte_vlan_strip(pkt); 183 | rte_eth_tx_burst(0, gen_port_q, &pkt, 1); 184 | rte_pktmbuf_free((*single_pkt)); 185 | new_pkt_num = 0; 186 | #endif 187 | } 188 | 189 | else { 190 | ip_hdr->hdr_checksum = 0; 191 | tcphdr = (struct rte_tcp_hdr *)(ip_hdr + 1); 192 | nat_tcp_learning(eth_hdr,ip_hdr,tcphdr,&new_port_id,vrg_ccb->ppp_ccb[user_index].addr_table); 193 | ip_hdr->src_addr = vrg_ccb->ppp_ccb[user_index].hsi_ipv4; 194 | tcphdr->src_port = rte_cpu_to_be_16(new_port_id); 195 | rte_atomic16_set(&vrg_ccb->ppp_ccb[user_index].addr_table[new_port_id].is_alive, 10); 196 | ip_hdr->hdr_checksum = rte_ipv4_cksum(ip_hdr); 197 | tcphdr->cksum = 0; 198 | tcphdr->cksum = rte_ipv4_udptcp_cksum(ip_hdr,tcphdr); 199 | 200 | new_pkt_num = 1; 201 | eth_hdr = (struct rte_ether_hdr *)rte_pktmbuf_prepend((*single_pkt), (U16)(sizeof(struct rte_ether_hdr) + sizeof(vlan_header_t) + sizeof(pppoe_header_t) + sizeof(ppp_payload_t))); 202 | /* for PPPoE */ 203 | rte_ether_addr_copy(&vrg_ccb->nic_info.hsi_wan_src_mac, ð_hdr->src_addr); 204 | rte_ether_addr_copy(&vrg_ccb->ppp_ccb[user_index].PPP_dst_mac, ð_hdr->dst_addr); 205 | eth_hdr->ether_type = rte_cpu_to_be_16(VLAN); 206 | vlan_header = (vlan_header_t *)(eth_hdr + 1); 207 | vlan_header->tci_union.tci_value = old_vlan_hdr.tci_union.tci_value; 208 | vlan_header->next_proto = rte_cpu_to_be_16(ETH_P_PPP_SES); 209 | 210 | pppoe_header = (pppoe_header_t *)(vlan_header + 1); 211 | pppoe_header->ver_type = VER_TYPE; 212 | pppoe_header->code = 0; 213 | pppoe_header->session_id = vrg_ccb->ppp_ccb[user_index].session_id; 214 | pppoe_header->length = rte_cpu_to_be_16(((*single_pkt)->data_len) - (U16)(sizeof(struct rte_ether_hdr) + sizeof(vlan_header_t) + sizeof(pppoe_header_t))); 215 | *(U16 *)(pppoe_header + 1) = rte_cpu_to_be_16(PPP_IP_PROTOCOL); 216 | } 217 | return new_pkt_num; 218 | } 219 | 220 | static int decaps_udp(VRG_t *vrg_ccb, struct rte_mbuf *single_pkt, struct rte_ether_hdr *eth_hdr, vlan_header_t *vlan_header, struct rte_ipv4_hdr *ip_hdr, U16 user_index) 221 | { 222 | struct rte_udp_hdr *udphdr; 223 | U16 ori_port_id; 224 | 225 | /*if (single_pkt->data_len > (ETH_MTU - (U16)(sizeof(pppoe_header_t) + sizeof(ppp_payload_t)))) { 226 | rte_pktmbuf_free(single_pkt); 227 | return 0; 228 | }*/ 229 | //single_pkt->ol_flags |= PKT_TX_IPV4 | PKT_TX_IP_CKSUM/* | PKT_TX_UDP_CKSUM*/; 230 | udphdr = (struct rte_udp_hdr *)(ip_hdr + 1); 231 | ori_port_id = rte_cpu_to_be_16(udphdr->dst_port); 232 | rte_ether_addr_copy(&vrg_ccb->nic_info.hsi_lan_mac, ð_hdr->src_addr); 233 | rte_ether_addr_copy(&vrg_ccb->ppp_ccb[user_index].addr_table[ori_port_id].mac_addr, ð_hdr->dst_addr); 234 | ip_hdr->dst_addr = vrg_ccb->ppp_ccb[user_index].addr_table[ori_port_id].src_ip; 235 | udphdr->dst_port = vrg_ccb->ppp_ccb[user_index].addr_table[ori_port_id].port_id; 236 | rte_atomic16_set(&vrg_ccb->ppp_ccb[user_index].addr_table[ori_port_id].is_alive, 10); 237 | ip_hdr->hdr_checksum = rte_ipv4_cksum(ip_hdr); 238 | udphdr->dgram_cksum = 0; 239 | udphdr->dgram_cksum = rte_ipv4_udptcp_cksum(ip_hdr,udphdr); 240 | 241 | return 1; 242 | } 243 | 244 | static int decaps_tcp(VRG_t *vrg_ccb, struct rte_mbuf *single_pkt, struct rte_ether_hdr *eth_hdr, vlan_header_t *vlan_header, struct rte_ipv4_hdr *ip_hdr, U16 user_index) 245 | { 246 | struct rte_tcp_hdr *tcphdr; 247 | U16 ori_port_id; 248 | 249 | /*if (single_pkt->data_len > (ETH_MTU - (U16)(sizeof(pppoe_header_t) + sizeof(ppp_payload_t)))) { 250 | rte_pktmbuf_free(single_pkt); 251 | return 0; 252 | }*/ 253 | //single_pkt->ol_flags |= PKT_TX_IPV4 | PKT_TX_IP_CKSUM/* | PKT_TX_TCP_CKSUM*/; 254 | tcphdr = (struct rte_tcp_hdr *)(ip_hdr + 1); 255 | ori_port_id = rte_cpu_to_be_16(tcphdr->dst_port); 256 | rte_ether_addr_copy(&vrg_ccb->nic_info.hsi_lan_mac, ð_hdr->src_addr); 257 | rte_ether_addr_copy(&vrg_ccb->ppp_ccb[user_index].addr_table[ori_port_id].mac_addr, ð_hdr->dst_addr); 258 | ip_hdr->dst_addr = vrg_ccb->ppp_ccb[user_index].addr_table[ori_port_id].src_ip; 259 | tcphdr->dst_port = vrg_ccb->ppp_ccb[user_index].addr_table[ori_port_id].port_id; 260 | rte_atomic16_set(&vrg_ccb->ppp_ccb[user_index].addr_table[ori_port_id].is_alive, 10); 261 | ip_hdr->hdr_checksum = rte_ipv4_cksum(ip_hdr); 262 | tcphdr->cksum = 0; 263 | tcphdr->cksum = rte_ipv4_udptcp_cksum(ip_hdr,tcphdr); 264 | 265 | return 1; 266 | } 267 | 268 | #endif -------------------------------------------------------------------------------- /src/dhcpd/dhcp_codec.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "dhcp_fsm.h" 9 | 10 | typedef struct dhcp_opt { 11 | U8 opt_type; 12 | U8 len; 13 | U8 val[0]; 14 | }dhcp_opt_t; 15 | 16 | typedef struct dhcp_info { 17 | U8 msg_type; 18 | U8 hwr_type; 19 | U8 hwr_addr_len; 20 | U8 hops; 21 | U32 transaction_id; 22 | U16 sec_elapsed; 23 | U16 bootp_flag; 24 | U32 client_ip; 25 | U32 ur_client_ip; 26 | U32 next_server_ip; 27 | U32 relay_agent_ip; 28 | struct rte_ether_addr mac_addr; 29 | unsigned char mac_addr_padding[10]; 30 | unsigned char server_name[64]; 31 | unsigned char file_name[128]; 32 | U32 magic_cookie; 33 | dhcp_opt_t opt_ptr[0]; 34 | }dhcp_info_t; 35 | 36 | STATUS decode_request(dhcp_ccb_t *dhcp_ccb); 37 | STATUS check_pool(dhcp_ccb_t *dhcp_ccb, struct rte_ether_addr mac_addr); 38 | static U16 ip_hdr_id = 1; 39 | 40 | BIT16 dhcp_decode(dhcp_ccb_t *dhcp_ccb, struct rte_ether_hdr *eth_hdr, vlan_header_t *vlan_header, struct rte_ipv4_hdr *ip_hdr, struct rte_udp_hdr *udp_hdr) 41 | { 42 | dhcp_opt_t *cur; 43 | BIT16 event = -1; 44 | 45 | dhcp_ccb->eth_hdr = eth_hdr; 46 | dhcp_ccb->vlan_hdr = vlan_header; 47 | dhcp_ccb->ip_hdr = ip_hdr; 48 | dhcp_ccb->udp_hdr = udp_hdr; 49 | dhcp_ccb->dhcp_info = (dhcp_info_t *)(udp_hdr + 1); 50 | cur = (dhcp_opt_t *)(dhcp_ccb->dhcp_info + 1); 51 | 52 | for(; cur->opt_type!=DHCP_END; cur=(dhcp_opt_t *)(((U8 *)(cur+1))+cur->len)) { 53 | if (cur->opt_type == DHCP_ISP_ID) 54 | return 0; 55 | else if (cur->opt_type == DHCP_MSG_TYPE) { 56 | switch (*(U8 *)(cur+1)) { 57 | case DHCP_DISCOVER: 58 | event = E_DISCOVER; 59 | break; 60 | case DHCP_REQUEST: 61 | if (decode_request(dhcp_ccb) == TRUE) 62 | event = E_GOOD_REQUEST; 63 | else 64 | event = E_BAD_REQUEST; 65 | rte_timer_stop(&dhcp_ccb->lan_user_info[dhcp_ccb->cur_lan_user_index].timer); 66 | break; 67 | case DHCP_RELEASE: 68 | if (check_pool(dhcp_ccb, eth_hdr->src_addr)) 69 | event = E_RELEASE; 70 | break; 71 | default: 72 | break; 73 | } 74 | } 75 | else if (cur->opt_type == DHCP_HOSTNAME) { 76 | } 77 | } 78 | return event; 79 | } 80 | 81 | STATUS check_pool(dhcp_ccb_t *dhcp_ccb, struct rte_ether_addr mac_addr) 82 | { 83 | U32 pool_index = (mac_addr.addr_bytes[0] + mac_addr.addr_bytes[1] + mac_addr.addr_bytes[2] + mac_addr.addr_bytes[3] + mac_addr.addr_bytes[4] + mac_addr.addr_bytes[5]) % MAX_IP_POOL; 84 | int i; 85 | 86 | for(i=pool_index; iip_pool[i].used == FALSE) { 88 | dhcp_ccb->cur_ip_pool_index = i; 89 | dhcp_ccb->ip_pool[i].used = TRUE; 90 | return TRUE; 91 | } 92 | else if (rte_is_same_ether_addr(&mac_addr, &dhcp_ccb->ip_pool[i].mac_addr)) { 93 | dhcp_ccb->cur_ip_pool_index = i; 94 | return TRUE; 95 | } 96 | } 97 | for(int j=0; jip_pool[j].used == FALSE) { 99 | dhcp_ccb->cur_ip_pool_index = j; 100 | dhcp_ccb->ip_pool[j].used = TRUE; 101 | return TRUE; 102 | } 103 | else if (rte_is_same_ether_addr(&mac_addr, &dhcp_ccb->ip_pool[j].mac_addr)) { 104 | dhcp_ccb->cur_ip_pool_index = j; 105 | return TRUE; 106 | } 107 | } 108 | 109 | return FALSE; 110 | } 111 | 112 | STATUS decode_request(dhcp_ccb_t *dhcp_ccb) 113 | { 114 | dhcp_opt_t *opt_ptr = (dhcp_opt_t *)(dhcp_ccb->dhcp_info + 1); 115 | dhcp_opt_t *cur = opt_ptr; 116 | struct rte_ether_addr mac_addr; 117 | 118 | rte_ether_addr_copy(&dhcp_ccb->eth_hdr->src_addr, &mac_addr); 119 | if (dhcp_ccb->dhcp_info->client_ip | RTE_IPV4_ANY) { 120 | dhcp_ccb->dhcp_info->ur_client_ip = dhcp_ccb->dhcp_info->client_ip; 121 | dhcp_ccb->dhcp_info->client_ip = 0; 122 | } 123 | else { 124 | for(; cur->opt_type!=DHCP_END; cur=(dhcp_opt_t *)(((U8 *)(cur+1))+cur->len)) { 125 | /*if (cur->opt_type == DHCP_CLIENT_ID) 126 | rte_ether_addr_copy((struct rte_ether_addr *)(cur->val), &mac_addr); 127 | else */if (cur->opt_type == DHCP_REQUEST_IP) 128 | rte_memcpy(&dhcp_ccb->dhcp_info->ur_client_ip, cur->val, 4); 129 | } 130 | } 131 | 132 | return check_pool(dhcp_ccb, mac_addr); 133 | } 134 | 135 | int pick_ip_from_pool(dhcp_ccb_t *dhcp_ccb, U32 *ip_addr, struct rte_ether_addr mac_addr) 136 | { 137 | U32 pool_index = (mac_addr.addr_bytes[0] + mac_addr.addr_bytes[1] + mac_addr.addr_bytes[2] + mac_addr.addr_bytes[3] + mac_addr.addr_bytes[4] + mac_addr.addr_bytes[5]) % MAX_IP_POOL; 138 | int i; 139 | 140 | for(i=pool_index; iip_pool[i].used == FALSE) { 142 | *ip_addr = dhcp_ccb->ip_pool[i].ip_addr; 143 | rte_ether_addr_copy(&mac_addr, &dhcp_ccb->ip_pool[i].mac_addr); 144 | dhcp_ccb->cur_ip_pool_index = i; 145 | return 0; 146 | } 147 | } 148 | for(int j=0; jip_pool[j].used == FALSE) { 150 | *ip_addr = dhcp_ccb->ip_pool[j].ip_addr; 151 | rte_ether_addr_copy(&mac_addr, &dhcp_ccb->ip_pool[j].mac_addr); 152 | dhcp_ccb->cur_ip_pool_index = j; 153 | return 0; 154 | } 155 | } 156 | return -1; 157 | } 158 | 159 | STATUS build_dhcp_offer(dhcp_ccb_t *dhcp_ccb) 160 | { 161 | struct rte_ether_addr macaddr; 162 | U32 ip_addr; 163 | 164 | rte_eth_macaddr_get(0, &macaddr); 165 | rte_ether_addr_copy(&dhcp_ccb->eth_hdr->src_addr, &dhcp_ccb->eth_hdr->dst_addr); 166 | rte_ether_addr_copy(&macaddr, &dhcp_ccb->eth_hdr->src_addr); 167 | if (pick_ip_from_pool(dhcp_ccb, &ip_addr, dhcp_ccb->eth_hdr->dst_addr) < 0) 168 | return FALSE; 169 | dhcp_ccb->ip_hdr->packet_id = ip_hdr_id++; 170 | dhcp_ccb->ip_hdr->packet_id = rte_cpu_to_be_16(dhcp_ccb->ip_hdr->packet_id); 171 | dhcp_ccb->ip_hdr->hdr_checksum = 0; 172 | dhcp_ccb->ip_hdr->src_addr = dhcp_ccb->dhcp_server_ip; 173 | dhcp_ccb->ip_hdr->dst_addr = ip_addr; 174 | dhcp_ccb->ip_hdr->total_length = (U16)sizeof(struct rte_ipv4_hdr); 175 | 176 | dhcp_ccb->udp_hdr->src_port = rte_cpu_to_be_16(67); 177 | dhcp_ccb->udp_hdr->dst_port = rte_cpu_to_be_16(68); 178 | dhcp_ccb->udp_hdr->dgram_cksum = 0; 179 | dhcp_ccb->udp_hdr->dgram_len = sizeof(struct rte_udp_hdr); 180 | 181 | dhcp_ccb->dhcp_info->msg_type = 0x2; 182 | dhcp_ccb->dhcp_info->ur_client_ip = ip_addr; 183 | dhcp_ccb->dhcp_info->next_server_ip = dhcp_ccb->dhcp_server_ip; 184 | dhcp_ccb->udp_hdr->dgram_len += sizeof(dhcp_info_t); 185 | 186 | unsigned char buf[128] = {0}; 187 | U32 dhcp_opt_len = 0; 188 | 189 | dhcp_opt_t *cur = (dhcp_opt_t *)buf; 190 | cur->opt_type = DHCP_MSG_TYPE; 191 | cur->len = sizeof(U8); 192 | *(cur->val) = DHCP_OFFER; 193 | dhcp_ccb->udp_hdr->dgram_len += sizeof(dhcp_opt_t) + cur->len; 194 | dhcp_opt_len += sizeof(dhcp_opt_t) + cur->len; 195 | 196 | cur = (dhcp_opt_t *)(((char *)cur) + sizeof(dhcp_opt_t) + cur->len); 197 | cur->opt_type = DHCP_SERVER_ID; 198 | cur->len = sizeof(dhcp_ccb->dhcp_server_ip); 199 | rte_memcpy(cur->val, &dhcp_ccb->dhcp_server_ip, cur->len); 200 | dhcp_ccb->udp_hdr->dgram_len += sizeof(dhcp_opt_t) + cur->len; 201 | dhcp_opt_len += sizeof(dhcp_opt_t) + cur->len; 202 | 203 | cur = (dhcp_opt_t *)(((char *)cur) + sizeof(dhcp_opt_t) + cur->len); 204 | cur->opt_type = DHCP_SUBNET_MASK; 205 | cur->len = sizeof(U32); // sizeof(255.255.255.0) 206 | cur->val[0] = 0x00; 207 | cur->val[1] = cur->val[2] = cur->val[3] = 0xff; 208 | dhcp_ccb->udp_hdr->dgram_len += sizeof(dhcp_opt_t) + cur->len; 209 | dhcp_opt_len += sizeof(dhcp_opt_t) + cur->len; 210 | 211 | cur = (dhcp_opt_t *)(((char *)cur) + sizeof(dhcp_opt_t) + cur->len); 212 | cur->opt_type = DHCP_LEASE_TIME; 213 | cur->len = sizeof(U32); 214 | U32 lease_time = rte_cpu_to_be_32(LEASE_TIMEOUT); //1 hr 215 | rte_memcpy(cur->val, &lease_time, cur->len); 216 | dhcp_ccb->udp_hdr->dgram_len += sizeof(dhcp_opt_t) + cur->len; 217 | dhcp_opt_len += sizeof(dhcp_opt_t) + cur->len; 218 | 219 | cur = (dhcp_opt_t *)(((char *)cur) + sizeof(dhcp_opt_t) + cur->len); 220 | cur->opt_type = DHCP_ROUTER; 221 | cur->len = sizeof(dhcp_ccb->dhcp_server_ip); 222 | rte_memcpy(cur->val, &dhcp_ccb->dhcp_server_ip, cur->len); 223 | dhcp_ccb->udp_hdr->dgram_len += sizeof(dhcp_opt_t) + cur->len; 224 | dhcp_opt_len += sizeof(dhcp_opt_t) + cur->len; 225 | 226 | cur = (dhcp_opt_t *)(((char *)cur) + sizeof(dhcp_opt_t) + cur->len); 227 | cur->opt_type = DHCP_DNS; 228 | cur->len = sizeof(U32) * 2; // 2 DNS servers 229 | U32 dns[2] = { rte_cpu_to_be_32(0x08080808), rte_cpu_to_be_32(0x01010101)}; 230 | rte_memcpy(cur->val, &dns, cur->len); 231 | dhcp_ccb->udp_hdr->dgram_len += sizeof(dhcp_opt_t) + cur->len; 232 | dhcp_opt_len += sizeof(dhcp_opt_t) + cur->len; 233 | 234 | cur = (dhcp_opt_t *)(((char *)cur) + sizeof(dhcp_opt_t) + cur->len); 235 | *(U8 *)cur = DHCP_END; 236 | memset(((U8 *)cur) + 1, 0, 22); 237 | dhcp_ccb->udp_hdr->dgram_len += sizeof(U8) + 22; 238 | dhcp_opt_len += sizeof(U8) + 22; 239 | 240 | rte_memcpy((dhcp_ccb->dhcp_info + 1), buf, dhcp_opt_len); 241 | 242 | dhcp_ccb->ip_hdr->total_length += dhcp_ccb->udp_hdr->dgram_len; 243 | //PRINT_MESSAGE(dhcp_ccb->eth_hdr, sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr) + sizeof(vlan_header_t) + dhcp_ccb->ip_hdr->total_length); 244 | 245 | dhcp_ccb->udp_hdr->dgram_len = rte_cpu_to_be_16(dhcp_ccb->udp_hdr->dgram_len); 246 | dhcp_ccb->ip_hdr->total_length = rte_cpu_to_be_16(dhcp_ccb->ip_hdr->total_length); 247 | dhcp_ccb->ip_hdr->hdr_checksum = rte_ipv4_cksum(dhcp_ccb->ip_hdr); 248 | 249 | return TRUE; 250 | } 251 | 252 | STATUS build_dhcp_ack(dhcp_ccb_t *dhcp_ccb) 253 | { 254 | struct rte_ether_addr macaddr; 255 | 256 | rte_eth_macaddr_get(0, &macaddr); 257 | rte_ether_addr_copy(&dhcp_ccb->eth_hdr->src_addr, &dhcp_ccb->eth_hdr->dst_addr); 258 | rte_ether_addr_copy(&macaddr, &dhcp_ccb->eth_hdr->src_addr); 259 | 260 | dhcp_ccb->ip_hdr->packet_id = ip_hdr_id++; 261 | dhcp_ccb->ip_hdr->packet_id = rte_cpu_to_be_16(dhcp_ccb->ip_hdr->packet_id); 262 | dhcp_ccb->ip_hdr->hdr_checksum = 0; 263 | dhcp_ccb->ip_hdr->src_addr = dhcp_ccb->dhcp_server_ip; 264 | dhcp_ccb->ip_hdr->dst_addr = dhcp_ccb->dhcp_info->ur_client_ip; 265 | dhcp_ccb->ip_hdr->total_length = sizeof(struct rte_ipv4_hdr); 266 | 267 | dhcp_ccb->udp_hdr->src_port = rte_cpu_to_be_16(67); 268 | dhcp_ccb->udp_hdr->dst_port = rte_cpu_to_be_16(68); 269 | dhcp_ccb->udp_hdr->dgram_cksum = 0; 270 | dhcp_ccb->udp_hdr->dgram_len = sizeof(struct rte_udp_hdr); 271 | 272 | dhcp_ccb->dhcp_info->msg_type = 0x2; 273 | dhcp_ccb->dhcp_info->next_server_ip = dhcp_ccb->dhcp_server_ip; 274 | dhcp_ccb->udp_hdr->dgram_len += sizeof(dhcp_info_t); 275 | 276 | unsigned char buf[128] = {0}; 277 | U32 dhcp_opt_len = 0; 278 | 279 | dhcp_opt_t *cur = (dhcp_opt_t *)buf; 280 | cur->opt_type = DHCP_MSG_TYPE; 281 | cur->len = sizeof(U8); 282 | *(cur->val) = DHCP_ACK; 283 | dhcp_ccb->udp_hdr->dgram_len += sizeof(dhcp_opt_t) + cur->len; 284 | dhcp_opt_len += sizeof(dhcp_opt_t) + cur->len; 285 | 286 | cur = (dhcp_opt_t *)(((char *)cur) + sizeof(dhcp_opt_t) + cur->len); 287 | cur->opt_type = DHCP_SERVER_ID; 288 | cur->len = sizeof(dhcp_ccb->dhcp_server_ip); 289 | rte_memcpy(cur->val, &dhcp_ccb->dhcp_server_ip, cur->len); 290 | dhcp_ccb->udp_hdr->dgram_len += sizeof(dhcp_opt_t) + cur->len; 291 | dhcp_opt_len += sizeof(dhcp_opt_t) + cur->len; 292 | 293 | cur = (dhcp_opt_t *)(((char *)cur) + sizeof(dhcp_opt_t) + cur->len); 294 | cur->opt_type = DHCP_SUBNET_MASK; 295 | cur->len = sizeof(U32); // sizeof(255.255.255.0) 296 | cur->val[3] = 0x00; 297 | cur->val[0] = cur->val[1] = cur->val[2] = 0xff; 298 | dhcp_ccb->udp_hdr->dgram_len += sizeof(dhcp_opt_t) + cur->len; 299 | dhcp_opt_len += sizeof(dhcp_opt_t) + cur->len; 300 | 301 | cur = (dhcp_opt_t *)(((char *)cur) + sizeof(dhcp_opt_t) + cur->len); 302 | cur->opt_type = DHCP_LEASE_TIME; 303 | cur->len = sizeof(U32); 304 | U32 lease_time = rte_cpu_to_be_32(LEASE_TIMEOUT); //1 hr 305 | rte_memcpy(cur->val, &lease_time, cur->len); 306 | dhcp_ccb->udp_hdr->dgram_len += sizeof(dhcp_opt_t) + cur->len; 307 | dhcp_opt_len += sizeof(dhcp_opt_t) + cur->len; 308 | 309 | cur = (dhcp_opt_t *)(((char *)cur) + sizeof(dhcp_opt_t) + cur->len); 310 | cur->opt_type = DHCP_ROUTER; 311 | cur->len = sizeof(dhcp_ccb->dhcp_server_ip); 312 | rte_memcpy(cur->val, &dhcp_ccb->dhcp_server_ip, cur->len); 313 | dhcp_ccb->udp_hdr->dgram_len += sizeof(dhcp_opt_t) + cur->len; 314 | dhcp_opt_len += sizeof(dhcp_opt_t) + cur->len; 315 | 316 | cur = (dhcp_opt_t *)(((char *)cur) + sizeof(dhcp_opt_t) + cur->len); 317 | cur->opt_type = DHCP_DNS; 318 | cur->len = sizeof(U32) * 2; // 2 DNS servers 319 | U32 dns[2] = { rte_cpu_to_be_32(0x08080808), rte_cpu_to_be_32(0x01010101) }; 320 | rte_memcpy(cur->val, &dns, cur->len); 321 | dhcp_ccb->udp_hdr->dgram_len += sizeof(dhcp_opt_t) + cur->len; 322 | dhcp_opt_len += sizeof(dhcp_opt_t) + cur->len; 323 | 324 | cur = (dhcp_opt_t *)(((char *)cur) + sizeof(dhcp_opt_t) + cur->len); 325 | *(U8 *)cur = DHCP_END; 326 | memset(((U8 *)cur) + 1, 0, 22); 327 | dhcp_ccb->udp_hdr->dgram_len += sizeof(U8) + 22; 328 | dhcp_opt_len += sizeof(U8) + 22; 329 | 330 | rte_memcpy((dhcp_ccb->dhcp_info + 1), buf, dhcp_opt_len); 331 | 332 | dhcp_ccb->ip_hdr->total_length += dhcp_ccb->udp_hdr->dgram_len; 333 | //PRINT_MESSAGE(dhcp_ccb->eth_hdr, sizeof(struct rte_ether_hdr) + sizeof(vlan_header_t) + sizeof(struct rte_ipv4_hdr) + dhcp_ccb->ip_hdr->total_length); 334 | 335 | dhcp_ccb->udp_hdr->dgram_len = rte_cpu_to_be_16(dhcp_ccb->udp_hdr->dgram_len); 336 | dhcp_ccb->ip_hdr->total_length = rte_cpu_to_be_16(dhcp_ccb->ip_hdr->total_length); 337 | dhcp_ccb->ip_hdr->hdr_checksum = rte_ipv4_cksum(dhcp_ccb->ip_hdr); 338 | 339 | return TRUE; 340 | } 341 | 342 | STATUS build_dhcp_nak(dhcp_ccb_t *dhcp_ccb) 343 | { 344 | struct rte_ether_addr macaddr; 345 | 346 | rte_eth_macaddr_get(0, &macaddr); 347 | rte_ether_addr_copy(&dhcp_ccb->eth_hdr->src_addr, &dhcp_ccb->eth_hdr->dst_addr); 348 | rte_ether_addr_copy(&macaddr, &dhcp_ccb->eth_hdr->src_addr); 349 | 350 | dhcp_ccb->ip_hdr->packet_id = ip_hdr_id++; 351 | dhcp_ccb->ip_hdr->packet_id = rte_cpu_to_be_16(dhcp_ccb->ip_hdr->packet_id); 352 | dhcp_ccb->ip_hdr->hdr_checksum = 0; 353 | dhcp_ccb->ip_hdr->src_addr = dhcp_ccb->dhcp_server_ip; 354 | dhcp_ccb->ip_hdr->dst_addr = dhcp_ccb->dhcp_info->ur_client_ip; 355 | dhcp_ccb->ip_hdr->total_length = sizeof(struct rte_ipv4_hdr); 356 | 357 | dhcp_ccb->udp_hdr->src_port = rte_cpu_to_be_16(67); 358 | dhcp_ccb->udp_hdr->dst_port = rte_cpu_to_be_16(68); 359 | dhcp_ccb->udp_hdr->dgram_cksum = 0; 360 | dhcp_ccb->udp_hdr->dgram_len = sizeof(struct rte_udp_hdr); 361 | 362 | dhcp_ccb->dhcp_info->client_ip = 0; 363 | dhcp_ccb->dhcp_info->ur_client_ip = 0; 364 | dhcp_ccb->dhcp_info->next_server_ip = 0; 365 | dhcp_ccb->dhcp_info->msg_type = 0x2; 366 | dhcp_ccb->dhcp_info->next_server_ip = dhcp_ccb->dhcp_server_ip; 367 | dhcp_ccb->udp_hdr->dgram_len += sizeof(dhcp_info_t); 368 | 369 | unsigned char buf[128] = {0}; 370 | U32 dhcp_opt_len = 0; 371 | 372 | dhcp_opt_t *cur = (dhcp_opt_t *)buf; 373 | cur->opt_type = DHCP_MSG_TYPE; 374 | cur->len = sizeof(U8); 375 | *(cur->val) = DHCP_NAK; 376 | dhcp_ccb->udp_hdr->dgram_len += sizeof(dhcp_opt_t) + cur->len; 377 | dhcp_opt_len += sizeof(dhcp_opt_t) + cur->len; 378 | 379 | cur = (dhcp_opt_t *)(((char *)cur) + sizeof(dhcp_opt_t) + cur->len); 380 | cur->opt_type = DHCP_SERVER_ID; 381 | cur->len = sizeof(dhcp_ccb->dhcp_server_ip); 382 | rte_memcpy(cur->val, &dhcp_ccb->dhcp_server_ip, cur->len); 383 | dhcp_ccb->udp_hdr->dgram_len += sizeof(dhcp_opt_t) + cur->len; 384 | dhcp_opt_len += sizeof(dhcp_opt_t) + cur->len; 385 | 386 | cur = (dhcp_opt_t *)(((char *)cur) + sizeof(dhcp_opt_t) + cur->len); 387 | cur->opt_type = DHCP_CLIENT_ID; 388 | cur->len = RTE_ETHER_ADDR_LEN; 389 | rte_ether_addr_copy(&dhcp_ccb->eth_hdr->dst_addr, (struct rte_ether_addr *)(cur->val)); 390 | dhcp_ccb->udp_hdr->dgram_len += sizeof(dhcp_opt_t) + cur->len; 391 | dhcp_opt_len += sizeof(dhcp_opt_t) + cur->len; 392 | 393 | cur = (dhcp_opt_t *)(((char *)cur) + sizeof(dhcp_opt_t) + cur->len); 394 | *(U8 *)cur = DHCP_END; 395 | memset(((U8 *)cur) + 1, 0, 22); 396 | dhcp_ccb->udp_hdr->dgram_len += sizeof(U8) + 22; 397 | dhcp_opt_len += sizeof(U8) + 22; 398 | 399 | rte_memcpy((dhcp_ccb->dhcp_info + 1), buf, dhcp_opt_len); 400 | 401 | dhcp_ccb->ip_hdr->total_length += dhcp_ccb->udp_hdr->dgram_len; 402 | //PRINT_MESSAGE(dhcp_ccb->eth_hdr, sizeof(struct rte_ether_hdr) + sizeof(vlan_header_t) + sizeof(struct rte_ipv4_hdr) + dhcp_ccb->ip_hdr->total_length); 403 | 404 | dhcp_ccb->udp_hdr->dgram_len = rte_cpu_to_be_16(dhcp_ccb->udp_hdr->dgram_len); 405 | dhcp_ccb->ip_hdr->total_length = rte_cpu_to_be_16(dhcp_ccb->ip_hdr->total_length); 406 | dhcp_ccb->ip_hdr->hdr_checksum = rte_ipv4_cksum(dhcp_ccb->ip_hdr); 407 | 408 | return TRUE; 409 | } 410 | -------------------------------------------------------------------------------- /northbound/grpc/vrg_node_grpc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "vrg_node_grpc.h" 6 | 7 | #ifdef __cplusplus 8 | extern "C" 9 | { 10 | #endif 11 | 12 | #include 13 | #include 14 | #include 15 | #include "../../src/vrg.h" 16 | 17 | #ifdef __cplusplus 18 | } 19 | #endif 20 | 21 | using namespace std; 22 | using namespace vrgnodeservice; 23 | 24 | extern struct rte_ring *rte_ring; 25 | 26 | grpc::Status VRGNodeServiceImpl::ConnectHsi(::grpc::ServerContext* context, const ::vrgnodeservice::HsiRequest* request, ::vrgnodeservice::HsiReply* response) 27 | { 28 | uint16_t user_id = request->user_id(), ccb_id = request->user_id() - 1; 29 | if (user_id > vrg_ccb->user_count) { 30 | std::string err = "Error! User " + std::to_string(user_id) + " is not exist"; 31 | cout << err << endl; 32 | return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, err); 33 | } 34 | 35 | cout << "ConnectHsi called" << endl; 36 | if (user_id == 0) { 37 | for(int i=0; iuser_count; i++) { 38 | if (vrg_ccb->vrg_switch[i].is_hsi_enable == VRG_SUBMODULE_IS_ENABLED || 39 | vrg_ccb->vrg_switch[i].is_hsi_enable == VRG_SUBMODULE_IS_SPAWNED || 40 | vrg_ccb->vrg_switch[i].is_hsi_enable == VRG_SUBMODULE_IS_SPAWNING) { 41 | cout << "User " << i + 1 << " is already connected" << endl; 42 | continue; 43 | } 44 | vrg_ccb->vrg_switch[i].is_hsi_enable = VRG_SUBMODULE_IS_ENABLED; 45 | } 46 | } else { 47 | if (vrg_ccb->vrg_switch[ccb_id].is_hsi_enable == VRG_SUBMODULE_IS_ENABLED || 48 | vrg_ccb->vrg_switch[ccb_id].is_hsi_enable == VRG_SUBMODULE_IS_SPAWNED || 49 | vrg_ccb->vrg_switch[ccb_id].is_hsi_enable == VRG_SUBMODULE_IS_SPAWNING) { 50 | cout << "User " << user_id << " is already connected" << endl; 51 | return grpc::Status::OK; 52 | } 53 | vrg_ccb->vrg_switch[ccb_id].is_hsi_enable = VRG_SUBMODULE_IS_ENABLED; 54 | } 55 | 56 | return grpc::Status::OK; 57 | } 58 | 59 | grpc::Status VRGNodeServiceImpl::DisconnectHsi(::grpc::ServerContext* context, const ::vrgnodeservice::HsiRequest* request, ::vrgnodeservice::HsiReply* response) 60 | { 61 | uint16_t user_id = request->user_id(), ccb_id = request->user_id() - 1; 62 | bool force = request->force(); 63 | 64 | if (user_id > vrg_ccb->user_count) { 65 | std::string err = "Error! User " + std::to_string(user_id) + " is not exist"; 66 | cout << err << endl; 67 | return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, err); 68 | } 69 | 70 | cout << "DisconnectHsi called" << endl; 71 | if (user_id == 0) { 72 | for(int i=0; iuser_count; i++) { 73 | if (force) { 74 | cout << "force disconnect" << i + 1 << endl; 75 | vrg_ccb->vrg_switch[i].is_hsi_enable = VRG_SUBMODULE_IS_FORCE_DISABLED; 76 | continue; 77 | } 78 | if (vrg_ccb->vrg_switch[i].is_hsi_enable == VRG_SUBMODULE_IS_DISABLED || 79 | vrg_ccb->vrg_switch[i].is_hsi_enable == VRG_SUBMODULE_IS_TERMINATED || 80 | vrg_ccb->vrg_switch[i].is_hsi_enable == VRG_SUBMODULE_IS_TERMINATING) { 81 | cout << "User " << i + 1 << " is already disconnected" << endl; 82 | continue; 83 | } 84 | vrg_ccb->vrg_switch[i].is_hsi_enable = VRG_SUBMODULE_IS_DISABLED; 85 | } 86 | } else { 87 | if (force) { 88 | cout << "force disconnect " << user_id << endl; 89 | vrg_ccb->vrg_switch[ccb_id].is_hsi_enable = VRG_SUBMODULE_IS_FORCE_DISABLED; 90 | return grpc::Status::OK; 91 | } 92 | if (vrg_ccb->vrg_switch[ccb_id].is_hsi_enable == VRG_SUBMODULE_IS_DISABLED || 93 | vrg_ccb->vrg_switch[ccb_id].is_hsi_enable == VRG_SUBMODULE_IS_TERMINATED || 94 | vrg_ccb->vrg_switch[ccb_id].is_hsi_enable == VRG_SUBMODULE_IS_TERMINATING) { 95 | cout << "User " << user_id << " is already disconnected" << endl; 96 | return grpc::Status::OK; 97 | } 98 | vrg_ccb->vrg_switch[ccb_id].is_hsi_enable = VRG_SUBMODULE_IS_DISABLED; 99 | } 100 | 101 | return grpc::Status::OK; 102 | } 103 | 104 | grpc::Status VRGNodeServiceImpl::DhcpServerStart(::grpc::ServerContext* context, const ::vrgnodeservice::DhcpServerRequest* request, ::vrgnodeservice::DhcpServerReply* response) 105 | { 106 | uint16_t user_id = request->user_id(), ccb_id = request->user_id() - 1; 107 | 108 | if (user_id > vrg_ccb->user_count) { 109 | std::string err = "Error! User " + std::to_string(user_id) + " is not exist"; 110 | cout << err << endl; 111 | return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, err); 112 | } 113 | 114 | cout << "DhcpServerStart called" << endl; 115 | if (user_id == 0) { 116 | std::string err; 117 | for(int i=0; iuser_count; i++) { 118 | if (vrg_ccb->vrg_switch[i].is_dhcp_server_enable == VRG_SUBMODULE_IS_ENABLED || 119 | vrg_ccb->vrg_switch[i].is_dhcp_server_enable == VRG_SUBMODULE_IS_SPAWNED || 120 | vrg_ccb->vrg_switch[i].is_dhcp_server_enable == VRG_SUBMODULE_IS_SPAWNING) { 121 | err += "User " + std::to_string(i + 1) + " dhcp server is already enabled\n"; 122 | continue; 123 | } 124 | vrg_ccb->vrg_switch[i].is_dhcp_server_enable = VRG_SUBMODULE_IS_ENABLED; 125 | } 126 | if (!err.empty()) 127 | return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, err); 128 | } else { 129 | if (vrg_ccb->vrg_switch[ccb_id].is_dhcp_server_enable == VRG_SUBMODULE_IS_ENABLED || 130 | vrg_ccb->vrg_switch[ccb_id].is_dhcp_server_enable == VRG_SUBMODULE_IS_SPAWNED || 131 | vrg_ccb->vrg_switch[ccb_id].is_dhcp_server_enable == VRG_SUBMODULE_IS_SPAWNING) { 132 | std::string err = "User " + std::to_string(user_id) + " dhcp server is already enabled"; 133 | return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, err); 134 | } 135 | vrg_ccb->vrg_switch[ccb_id].is_dhcp_server_enable = VRG_SUBMODULE_IS_ENABLED; 136 | } 137 | 138 | return grpc::Status::OK; 139 | } 140 | 141 | grpc::Status VRGNodeServiceImpl::DhcpServerStop(::grpc::ServerContext* context, const ::vrgnodeservice::DhcpServerRequest* request, ::vrgnodeservice::DhcpServerReply* response) 142 | { 143 | uint16_t user_id = request->user_id(), ccb_id = request->user_id() - 1; 144 | 145 | if (user_id > vrg_ccb->user_count) { 146 | std::string err = "Error! User " + std::to_string(user_id) + " is not exist"; 147 | cout << err << endl; 148 | return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, err); 149 | } 150 | 151 | cout << "DhcpServerStop called" << endl; 152 | if (user_id == 0) { 153 | std::string err; 154 | for(int i=0; iuser_count; i++) { 155 | if (vrg_ccb->vrg_switch[i].is_dhcp_server_enable == VRG_SUBMODULE_IS_DISABLED || 156 | vrg_ccb->vrg_switch[i].is_dhcp_server_enable == VRG_SUBMODULE_IS_TERMINATED || 157 | vrg_ccb->vrg_switch[i].is_dhcp_server_enable == VRG_SUBMODULE_IS_TERMINATING) { 158 | err += "User " + std::to_string(i + 1) + " dhcp server is already disabled\n"; 159 | continue; 160 | } 161 | vrg_ccb->vrg_switch[i].is_dhcp_server_enable = VRG_SUBMODULE_IS_DISABLED; 162 | } 163 | if (!err.empty()) 164 | return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, err); 165 | } else { 166 | if (vrg_ccb->vrg_switch[ccb_id].is_dhcp_server_enable == VRG_SUBMODULE_IS_DISABLED || 167 | vrg_ccb->vrg_switch[ccb_id].is_dhcp_server_enable == VRG_SUBMODULE_IS_TERMINATED || 168 | vrg_ccb->vrg_switch[ccb_id].is_dhcp_server_enable == VRG_SUBMODULE_IS_TERMINATING) { 169 | std::string err = "User " + std::to_string(user_id) + " dhcp server is already disabled"; 170 | return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, err); 171 | } 172 | vrg_ccb->vrg_switch[ccb_id].is_dhcp_server_enable = VRG_SUBMODULE_IS_DISABLED; 173 | } 174 | 175 | return grpc::Status::OK; 176 | } 177 | 178 | int getNicInfo(NicDriverInfo *nic_info, uint8_t port_id) 179 | { 180 | struct rte_eth_dev_info dev_info = {0}; 181 | if (rte_eth_dev_info_get(port_id, &dev_info) != 0) { 182 | std::string err = "get device info failed"; 183 | return -1; 184 | } 185 | nic_info->set_driver_name(std::string(dev_info.driver_name)); 186 | char buf[RTE_ETH_NAME_MAX_LEN]; 187 | if (rte_eth_dev_get_name_by_port(port_id, buf) != 0) { 188 | std::string err = "get device pci addr failed"; 189 | return -1; 190 | } 191 | nic_info->set_pci_addr(std::string(buf)); 192 | 193 | return 0; 194 | } 195 | 196 | int getNicStats(Statistics *stats, uint8_t port_id) 197 | { 198 | struct rte_eth_stats eth_stats = {0}; 199 | if (rte_eth_stats_get(port_id, ð_stats) != 0) { 200 | std::string err = "get device stats failed"; 201 | return -1; 202 | } 203 | stats->set_rx_packets(eth_stats.ipackets); 204 | stats->set_tx_packets(eth_stats.opackets); 205 | stats->set_rx_bytes(eth_stats.ibytes); 206 | stats->set_tx_bytes(eth_stats.obytes); 207 | stats->set_rx_errors(eth_stats.ierrors); 208 | stats->set_tx_errors(eth_stats.oerrors); 209 | stats->set_rx_dropped(eth_stats.imissed); 210 | 211 | return 0; 212 | } 213 | 214 | grpc::Status VRGNodeServiceImpl::GetVrgSystemInfo(::grpc::ServerContext* context, const ::google::protobuf::Empty* request, ::vrgnodeservice::VrgSystemInfo* response) 215 | { 216 | uint8_t lan_port_id = 0, wan_port_id = 1; 217 | 218 | cout << "GetVrgSystemInfo called" << endl; 219 | VrgBaseInfo* base_info = response->mutable_base_info(); 220 | base_info->set_vrg_version(std::string(vrg_ccb->version)); 221 | base_info->set_build_date(std::string(vrg_ccb->build_date)); 222 | base_info->set_dpdk_version(std::string(rte_version())); 223 | base_info->set_dpdk_eal_args(std::string(vrg_ccb->eal_args)); 224 | base_info->set_num_users(vrg_ccb->user_count); 225 | 226 | NicDriverInfo *lan_nic_info = response->add_nics(); 227 | if (getNicInfo(lan_nic_info, lan_port_id) != 0) { 228 | std::string err = "get lan device info failed"; 229 | return grpc::Status(grpc::StatusCode::INTERNAL, err); 230 | } 231 | // mac addr 232 | lan_nic_info->set_mac_addr(std::string( 233 | reinterpret_cast(vrg_ccb->nic_info.hsi_lan_mac.addr_bytes), 6)); 234 | 235 | NicDriverInfo *wan_nic_info = response->add_nics(); 236 | if (getNicInfo(wan_nic_info, wan_port_id) != 0) { 237 | std::string err = "get wan device info failed"; 238 | return grpc::Status(grpc::StatusCode::INTERNAL, err); 239 | } 240 | // mac addr 241 | wan_nic_info->set_mac_addr(std::string( 242 | reinterpret_cast(vrg_ccb->nic_info.hsi_wan_src_mac.addr_bytes), 6)); 243 | 244 | Statistics *lan_stats = response->add_stats(); 245 | if (getNicStats(lan_stats, lan_port_id) != 0) { 246 | std::string err = "get lan device stats failed"; 247 | return grpc::Status(grpc::StatusCode::INTERNAL, err); 248 | } 249 | Statistics *wan_stats = response->add_stats(); 250 | if (getNicStats(wan_stats, wan_port_id) != 0) { 251 | std::string err = "get wan device stats failed"; 252 | return grpc::Status(grpc::StatusCode::INTERNAL, err); 253 | } 254 | 255 | return grpc::Status::OK; 256 | } 257 | 258 | grpc::Status VRGNodeServiceImpl::GetVrgHsiInfo(::grpc::ServerContext* context, const ::google::protobuf::Empty* request, ::vrgnodeservice::VrgHsiInfo* response) 259 | { 260 | cout << "GetVrgHsiInfo called" << endl; 261 | for(int i=0; iuser_count; i++) { 262 | HsiInfo* hsi_info = response->add_hsi_infos(); 263 | hsi_info->set_user_id(i + 1); 264 | hsi_info->set_vlan_id(vrg_ccb->ppp_ccb[i].vlan); 265 | switch (vrg_ccb->ppp_ccb[i].phase) { 266 | case END_PHASE: 267 | hsi_info->set_status("init phase"); 268 | break; 269 | case PPPOE_PHASE: 270 | hsi_info->set_status("pppoe phase"); 271 | break; 272 | case LCP_PHASE: 273 | hsi_info->set_status("lcp phase"); 274 | break; 275 | case AUTH_PHASE: 276 | hsi_info->set_status("auth phase"); 277 | break; 278 | case IPCP_PHASE: 279 | hsi_info->set_status("ipcp phase"); 280 | break; 281 | case DATA_PHASE: 282 | hsi_info->set_status("PPPoE connection"); 283 | hsi_info->set_account(std::string(reinterpret_cast(vrg_ccb->ppp_ccb->ppp_user_id))); 284 | hsi_info->set_password(std::string(reinterpret_cast(vrg_ccb->ppp_ccb->ppp_passwd))); 285 | hsi_info->set_session_id(rte_be_to_cpu_16(vrg_ccb->ppp_ccb->session_id)); 286 | hsi_info->set_ip_addr(std::to_string(*(((U8 *)&(vrg_ccb->ppp_ccb[i].hsi_ipv4)))) + "." + 287 | std::to_string(*(((U8 *)&(vrg_ccb->ppp_ccb[i].hsi_ipv4))+1)) + "." + 288 | std::to_string(*(((U8 *)&(vrg_ccb->ppp_ccb[i].hsi_ipv4))+2)) + "." + 289 | std::to_string(*(((U8 *)&(vrg_ccb->ppp_ccb[i].hsi_ipv4))+3))); 290 | hsi_info->set_gateway(std::to_string(*(((U8 *)&(vrg_ccb->ppp_ccb[i].hsi_ipv4_gw)))) + "." + 291 | std::to_string(*(((U8 *)&(vrg_ccb->ppp_ccb[i].hsi_ipv4_gw))+1)) + "." + 292 | std::to_string(*(((U8 *)&(vrg_ccb->ppp_ccb[i].hsi_ipv4_gw))+2)) + "." + 293 | std::to_string(*(((U8 *)&(vrg_ccb->ppp_ccb[i].hsi_ipv4_gw))+3))); 294 | hsi_info->add_dnss(std::to_string(*(((U8 *)&(vrg_ccb->ppp_ccb[i].hsi_primary_dns)))) + "." + 295 | std::to_string(*(((U8 *)&(vrg_ccb->ppp_ccb[i].hsi_primary_dns))+1)) + "." + 296 | std::to_string(*(((U8 *)&(vrg_ccb->ppp_ccb[i].hsi_primary_dns))+2)) + "." + 297 | std::to_string(*(((U8 *)&(vrg_ccb->ppp_ccb[i].hsi_primary_dns))+3))); 298 | hsi_info->add_dnss(std::to_string(*(((U8 *)&(vrg_ccb->ppp_ccb[i].hsi_second_dns)))) + "." + 299 | std::to_string(*(((U8 *)&(vrg_ccb->ppp_ccb[i].hsi_second_dns))+1)) + "." + 300 | std::to_string(*(((U8 *)&(vrg_ccb->ppp_ccb[i].hsi_second_dns))+2)) + "." + 301 | std::to_string(*(((U8 *)&(vrg_ccb->ppp_ccb[i].hsi_second_dns))+3))); 302 | break; 303 | default: 304 | hsi_info->set_status("unknown status"); 305 | break; 306 | } 307 | } 308 | 309 | return grpc::Status::OK; 310 | } 311 | 312 | grpc::Status VRGNodeServiceImpl::GetVrgDhcpInfo(::grpc::ServerContext* context, const ::google::protobuf::Empty* request, ::vrgnodeservice::VrgDhcpInfo* response) 313 | { 314 | cout << "GetVrgDhcpInfo called" << endl; 315 | dhcp_ccb_t *dhcp_ccb = vrg_ccb->dhcp_ccb; 316 | for(int i=0; iuser_count; i++) { 317 | DhcpInfo* dhcp_info = response->add_dhcp_infos(); 318 | if (rte_atomic16_read(&vrg_ccb->dhcp_ccb[i].dhcp_bool) == 1) { 319 | dhcp_info->set_user_id(i + 1); 320 | dhcp_info->set_status("DHCP server is on"); 321 | 322 | for(U8 j=0; jadd_inuse_ips(std::to_string(*(((U8 *)&(dhcp_ccb[i].ip_pool[j].ip_addr)))) + "." + 325 | std::to_string(*(((U8 *)&(dhcp_ccb[i].ip_pool[j].ip_addr))+1)) + "." + 326 | std::to_string(*(((U8 *)&(dhcp_ccb[i].ip_pool[j].ip_addr))+2)) + "." + 327 | std::to_string(*(((U8 *)&(dhcp_ccb[i].ip_pool[j].ip_addr))+3))); 328 | } 329 | } 330 | } 331 | else { 332 | dhcp_info->set_user_id(i + 1); 333 | dhcp_info->set_status("DHCP server is off"); 334 | } 335 | 336 | dhcp_info->set_start_ip(std::to_string(*(((U8 *)&(dhcp_ccb[i].ip_pool[0].ip_addr)))) + "." + 337 | std::to_string(*(((U8 *)&(dhcp_ccb[i].ip_pool[0].ip_addr))+1)) + "." + 338 | std::to_string(*(((U8 *)&(dhcp_ccb[i].ip_pool[0].ip_addr))+2)) + "." + 339 | std::to_string(*(((U8 *)&(dhcp_ccb[i].ip_pool[0].ip_addr))+3))); 340 | dhcp_info->set_end_ip(std::to_string(*(((U8 *)&(dhcp_ccb[i].ip_pool[MAX_IP_POOL - 1].ip_addr)))) + "." + 341 | std::to_string(*(((U8 *)&(dhcp_ccb[i].ip_pool[MAX_IP_POOL - 1].ip_addr))+1)) + "." + 342 | std::to_string(*(((U8 *)&(dhcp_ccb[i].ip_pool[MAX_IP_POOL - 1].ip_addr))+2)) + "." + 343 | std::to_string(*(((U8 *)&(dhcp_ccb[i].ip_pool[MAX_IP_POOL - 1].ip_addr))+3))); 344 | dhcp_info->set_subnet_mask("255.255.255.0"); 345 | dhcp_info->set_gateway(std::to_string(*(((U8 *)&(dhcp_ccb[i].dhcp_server_ip)))) + "." + 346 | std::to_string(*(((U8 *)&(dhcp_ccb[i].dhcp_server_ip))+1)) + "." + 347 | std::to_string(*(((U8 *)&(dhcp_ccb[i].dhcp_server_ip))+2)) + "." + 348 | std::to_string(*(((U8 *)&(dhcp_ccb[i].dhcp_server_ip))+3))); 349 | } 350 | return grpc::Status::OK; 351 | } 352 | 353 | grpc::Status VRGNodeServiceImpl::GetNodeStatus(::grpc::ServerContext* context, const ::google::protobuf::Empty* request, ::vrgnodeservice::NodeStatus* response) 354 | { 355 | cout << "GetNodeStatus called" << endl; 356 | 357 | // get os version 358 | std::string os_name; 359 | struct utsname buffer; 360 | if (uname(&buffer) == 0) { 361 | os_name = std::string(buffer.sysname) + " " + std::string(buffer.release); 362 | } else { 363 | std::string err = "Failed to get Linux kernel version"; 364 | return grpc::Status(grpc::StatusCode::INTERNAL, err); 365 | } 366 | std::ifstream os_release("/etc/os-release"); 367 | if (os_release.is_open()) { 368 | std::string line, name, version; 369 | while (std::getline(os_release, line)) { 370 | if (line.rfind("PRETTY_NAME=", 0) == 0) { 371 | std::string value = line.substr(12); // remove PRETTY_NAME=" 372 | if (!value.empty() && value.front() == '"' && value.back() == '"') { 373 | value = value.substr(1, value.size() - 2); 374 | } 375 | os_name += " " + value; 376 | break; 377 | } 378 | } 379 | os_release.close(); 380 | } else { 381 | std::string err = "Failed to open /etc/os-release"; 382 | return grpc::Status(grpc::StatusCode::INTERNAL, err); 383 | } 384 | response->set_node_os_version(os_name); 385 | 386 | std::ifstream uptime_file("/proc/uptime"); 387 | if (!uptime_file.is_open()) { 388 | std::string err = "Failed to get system uptime"; 389 | return grpc::Status(grpc::StatusCode::INTERNAL, err); 390 | } 391 | double uptime_seconds; 392 | uptime_file >> uptime_seconds; 393 | uptime_file.close(); 394 | response->set_node_uptime(static_cast(uptime_seconds)); 395 | 396 | FILE* fp = popen("ip route show default 2>/dev/null", "r"); 397 | std::string def_route; 398 | if (fp) { 399 | char buf[256]; 400 | if (fgets(buf, sizeof(buf), fp)) { 401 | def_route = buf; 402 | } 403 | pclose(fp); 404 | } else { 405 | std::string err = "Failed to get default route"; 406 | return grpc::Status(grpc::StatusCode::INTERNAL, err); 407 | } 408 | 409 | std::string iface; 410 | if (!def_route.empty()) { 411 | std::istringstream iss(def_route); 412 | std::string word; 413 | while (iss >> word) { 414 | if (word == "dev") { 415 | iss >> iface; 416 | break; 417 | } 418 | } 419 | } else { 420 | std::string err = "No default route found"; 421 | return grpc::Status(grpc::StatusCode::INTERNAL, err); 422 | } 423 | 424 | if (!iface.empty()) { 425 | struct ifaddrs *ifaddr, *ifa; 426 | if (getifaddrs(&ifaddr) == 0) { 427 | for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { 428 | if (ifa->ifa_addr == NULL) continue; 429 | if (iface == ifa->ifa_name && ifa->ifa_addr->sa_family == AF_INET) { 430 | char ip[INET_ADDRSTRLEN]; 431 | void* addr = &((struct sockaddr_in*)ifa->ifa_addr)->sin_addr; 432 | inet_ntop(AF_INET, addr, ip, sizeof(ip)); 433 | 434 | char netmask[INET_ADDRSTRLEN]; 435 | void* mask = &((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr; 436 | inet_ntop(AF_INET, mask, netmask, sizeof(netmask)); 437 | 438 | response->set_node_ip_info(std::string(ip) + "/" + std::string(netmask)); 439 | } 440 | } 441 | freeifaddrs(ifaddr); 442 | } 443 | } else { 444 | std::string err = "No default route interface found."; 445 | return grpc::Status(grpc::StatusCode::INTERNAL, err); 446 | } 447 | 448 | response->set_healthy(true); 449 | 450 | return grpc::Status::OK; 451 | } 452 | -------------------------------------------------------------------------------- /unit_test/pppd/codec_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../../src/pppd/codec.h" 5 | #include "../../src/protocol.h" 6 | 7 | void test_build_padi() { 8 | U8 buffer[80] = { 0 }; 9 | U16 mulen; 10 | 11 | PPP_INFO_t s_ppp_ccb_1 = { 12 | .pppoe_phase = { 13 | .timer_counter = 0, 14 | .max_retransmit = 10, 15 | }, 16 | .user_num = 1, 17 | .vlan = 2, 18 | }; 19 | U8 pkt_1[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9c, 0x69, 0xb4, 0x61, 20 | 0x16, 0xdd, 0x81, 0x00, 0x00, 0x02, 0x88, 0x63, 0x11, 0x09, 0x00, 0x00, 0x00, 21 | 0x04, 0x01, 0x01, 0x00, 0x00}; 22 | 23 | assert(build_padi(buffer, &mulen, &s_ppp_ccb_1) == SUCCESS); 24 | assert(mulen == sizeof(pkt_1)); 25 | assert(memcmp(buffer, pkt_1, mulen) == 0); 26 | 27 | // TODO: move timeout test to send_pkt() 28 | /*memset(buffer, 0, sizeof(buffer)); 29 | s_ppp_ccb_1.pppoe_phase.timer_counter = 10; 30 | assert(build_padi(buffer, &mulen, &s_ppp_ccb_1) == ERROR);*/ 31 | } 32 | 33 | void test_build_padr() { 34 | U8 buffer[80] = { 0 }; 35 | U16 mulen = 0; 36 | struct rte_ether_hdr eth_hdr = { 37 | .ether_type = htons(VLAN), 38 | }; 39 | vlan_header_t vlan_header = { 40 | .tci_union.tci_value = htons(0002), 41 | .next_proto = htons(ETH_P_PPP_DIS), 42 | }; 43 | pppoe_header_t pppoe_header = { 44 | .code = PADO, 45 | .ver_type = 0x11, 46 | .session_id = htons(0x000a), 47 | .length = htons(0x002c), 48 | }; 49 | 50 | PPP_INFO_t s_ppp_ccb_1 = { 51 | .pppoe_phase = { 52 | .timer_counter = 0, 53 | .max_retransmit = 10, 54 | }, 55 | .user_num = 1, 56 | .vlan = 2, 57 | .PPP_dst_mac = (struct rte_ether_addr){ 58 | .addr_bytes = {0x74, 0x4d, 0x28, 0x8d, 0x00, 0x31}, 59 | }, 60 | .eth_hdr = eth_hdr, 61 | .vlan_header = vlan_header, 62 | .pppoe_header = pppoe_header, 63 | }; 64 | U8 pppoe_header_tag[44] = {0x01, 0x03, 0x00, 0x04, 0xdb, 0xce, 0x00, 0x00, 65 | 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x08, 0x4d, 0x69, 0x6b, 0x72, 66 | 0x6f, 0x54, 0x69, 0x6b, 0x01, 0x01, 0x00, 0x10, 0x76, 0x72, 0x67, 0x5f, 67 | 0x73, 0x65, 0x72, 0x76, 0x65, 0x72}; 68 | s_ppp_ccb_1.pppoe_phase.pppoe_header_tag = (pppoe_header_tag_t *)pppoe_header_tag; 69 | char pkt_1[] = {0x74, 0x4d, 0x28, 0x8d, 0x00, 0x31, 0x9c, 0x69, 0xb4, 0x61, 70 | 0x16, 0xdd, 0x81, 0x00, 0x00, 0x02, 0x88, 0x63, 0x11, 0x19, 0x00, 0x0a, 0x00, 71 | 0x0c, 0x01, 0x01, 0x00, 0x00, 0x01, 0x03, 0x00, 0x04, 0xdb, 0xce, 0x00, 0x00}; 72 | 73 | assert(build_padr(buffer, &mulen, &s_ppp_ccb_1) == SUCCESS); 74 | assert(mulen == sizeof(pkt_1)); 75 | assert(memcmp(buffer, pkt_1, mulen) == 0); 76 | 77 | // TODO: move timeout test to send_pkt() 78 | /*memset(buffer, 0, sizeof(buffer)); 79 | s_ppp_ccb_1.pppoe_phase.timer_counter = 10; 80 | assert(build_padr(buffer, &mulen, &s_ppp_ccb_1) == ERROR);*/ 81 | } 82 | 83 | void test_build_padt() { 84 | U8 buffer[80] = { 0 }; 85 | U16 mulen = 0; 86 | struct rte_ether_hdr eth_hdr = { 87 | .ether_type = htons(VLAN), 88 | }; 89 | vlan_header_t vlan_header = { 90 | .tci_union.tci_value = htons(0002), 91 | .next_proto = htons(ETH_P_PPP_DIS), 92 | }; 93 | pppoe_header_t pppoe_header = { 94 | .code = PADS, 95 | .ver_type = 0x11, 96 | .session_id = htons(0x000a), 97 | .length = htons(0x002c), 98 | }; 99 | 100 | PPP_INFO_t s_ppp_ccb_1 = { 101 | .pppoe_phase = { 102 | .timer_counter = 0, 103 | .max_retransmit = 10, 104 | }, 105 | .user_num = 1, 106 | .vlan = 2, 107 | .PPP_dst_mac = (struct rte_ether_addr){ 108 | .addr_bytes = {0x74, 0x4d, 0x28, 0x8d, 0x00, 0x31}, 109 | }, 110 | .session_id = htons(0x000a), 111 | .eth_hdr = eth_hdr, 112 | .vlan_header = vlan_header, 113 | .pppoe_header = pppoe_header, 114 | }; 115 | char pkt_1[] = {0x74, 0x4d, 0x28, 0x8d, 0x00, 0x31, 0x9c, 0x69, 0xb4, 0x61, 116 | 0x16, 0xdd, 0x81, 0x00, 0x00, 0x02, 0x88, 0x63, 0x11, 0xa7, 0x00, 0x0a, 0x00, 117 | 0x00}; 118 | 119 | build_padt(buffer, &mulen, &s_ppp_ccb_1); 120 | assert(mulen == sizeof(pkt_1)); 121 | assert(memcmp(buffer, pkt_1, mulen) == 0); 122 | } 123 | 124 | void test_build_config_request() { 125 | U8 buffer[80] = { 0 }; 126 | U16 mulen = 0; 127 | 128 | PPP_INFO_t s_ppp_ccb[] = { 129 | { 130 | .ppp_phase = {{ 131 | .timer_counter = 0, 132 | .max_retransmit = 10, 133 | },{ 134 | .timer_counter = 0, 135 | .max_retransmit = 10, 136 | },}, 137 | .user_num = 1, 138 | .vlan = 2, 139 | .PPP_dst_mac = (struct rte_ether_addr){ 140 | .addr_bytes = {0x74, 0x4d, 0x28, 0x8d, 0x00, 0x31}, 141 | }, 142 | .session_id = htons(0x000a), 143 | .cp = 0, 144 | .magic_num = htonl(0x01020304), 145 | .identifier = 0xfd, 146 | .hsi_ipv4 = 0x0, 147 | }, 148 | }; 149 | 150 | U8 pkt_lcp[] = {/* mac */0x74, 0x4d, 0x28, 0x8d, 0x00, 0x31, 0x9c, 0x69, 0xb4, 151 | 0x61, 0x16, 0xdd, 0x81, 0x00, /* vlan */0x00, 0x02, 0x88, 0x64, /* pppoe hdr */ 152 | 0x11, 0x00, 0x00, 0x0a, 0x00, 0x10, /* ppp protocol */0xc0, 0x21, /* ppp hdr */ 153 | 0x01, 0xfe, 0x00, 0x0e, /* ppp option */0x01, 0x04, 0x05, 0xd0, 0x05, 0x06, 0x01, 154 | 0x02, 0x03, 0x04}; 155 | U8 pkt_ipcp_1[] = {/* mac */0x74, 0x4d, 0x28, 0x8d, 0x00, 0x31, 0x9c, 0x69, 0xb4, 156 | 0x61, 0x16, 0xdd, 0x81, 0x00, /* vlan */0x00, 0x02, 0x88, 0x64, /* pppoe hdr */ 157 | 0x11, 0x00, 0x00, 0x0a, 0x00, 0x0c, /* ppp protocol */0x80, 0x21, /* ppp hdr */ 158 | 0x01, 0xff, 0x00, 0x0a, /* ppp option */0x03, 0x06, 0x00, 0x00, 0x00, 0x00}; 159 | U8 pkt_ipcp_2[] = {/* mac */0x74, 0x4d, 0x28, 0x8d, 0x00, 0x31, 0x9c, 0x69, 0xb4, 160 | 0x61, 0x16, 0xdd, 0x81, 0x00, /* vlan */0x00, 0x02, 0x88, 0x64, /* pppoe hdr */ 161 | 0x11, 0x00, 0x00, 0x0a, 0x00, 0x0c, /* ppp protocol */0x80, 0x21, /* ppp hdr */ 162 | 0x01, 0x01, 0x00, 0x0a, /* ppp option */0x03, 0x06, 0xc0, 0xa8, 0xc8, 0x01}; 163 | 164 | for(int i=0; icode == TERMIN_REQUEST); 299 | assert(test_ppp_hdr->length == htons(0x0004)); 300 | 301 | /* test IPCP */ 302 | memset(buffer, 0, sizeof(buffer)); 303 | s_ppp_ccb_1.cp = 1; 304 | build_terminate_request(buffer, &mulen, &s_ppp_ccb_1); 305 | assert(mulen == sizeof(pkt_ipcp)); 306 | assert(memcmp(buffer, pkt_ipcp, 26/* only memcmp to ipcp field */) == 0); 307 | test_ppp_hdr = (ppp_header_t *)(buffer + 26); 308 | assert(test_ppp_hdr->code == TERMIN_REQUEST); 309 | assert(test_ppp_hdr->length == htons(0x0004)); 310 | } 311 | 312 | void test_build_config_nak_rej() 313 | { 314 | U8 buffer[80] = {0}; 315 | U16 mulen = 0; 316 | 317 | PPP_INFO_t s_ppp_ccb_1 = { 318 | .ppp_phase = {{ 319 | .timer_counter = 0, 320 | .max_retransmit = 10, 321 | .ppp_payload = (ppp_payload_t) { 322 | .ppp_protocol = htons(LCP_PROTOCOL), 323 | }, 324 | .ppp_hdr = (ppp_header_t) { 325 | .code = CONFIG_REJECT, 326 | .identifier = 0x01, 327 | .length = htons(0x0008), 328 | }, 329 | .ppp_options = (ppp_options_t *)(U8 []){ 330 | 0x03, 0x04, 0xc0, 0x23 331 | }, // CHAP 332 | },{ 333 | .timer_counter = 0, 334 | .max_retransmit = 10, 335 | .ppp_payload = (ppp_payload_t) { 336 | .ppp_protocol = htons(IPCP_PROTOCOL), 337 | }, 338 | .ppp_hdr = (ppp_header_t) { 339 | .code = CONFIG_REJECT, 340 | .identifier = 0x01, 341 | .length = htons(0x000a), 342 | }, 343 | .ppp_options = (ppp_options_t *)(U8 []){ 344 | 0x83, 0x06, 0x00, 0x00, 0x00, 0x00 345 | }, // Secondary DNS 346 | },}, 347 | .user_num = 1, 348 | .vlan = 2, 349 | .PPP_dst_mac = (struct rte_ether_addr){ 350 | .addr_bytes = {0x74, 0x4d, 0x28, 0x8d, 0x00, 0x31}, 351 | }, 352 | .session_id = htons(0x000a), 353 | .cp = 0, 354 | .eth_hdr = (struct rte_ether_hdr) { 355 | .ether_type = htons(VLAN), 356 | }, 357 | .vlan_header = (vlan_header_t) { 358 | .tci_union.tci_value = htons(0002), 359 | .next_proto = htons(ETH_P_PPP_SES), 360 | }, 361 | .pppoe_header = (pppoe_header_t) { 362 | .code = 0, 363 | .ver_type = 0x11, 364 | .session_id = htons(0x000a), 365 | .length = htons(0x000a), 366 | }, 367 | }; 368 | PPP_INFO_t s_ppp_ccb_2 = { 369 | .ppp_phase = {{ 370 | .timer_counter = 0, 371 | .max_retransmit = 10, 372 | .ppp_payload = (ppp_payload_t) { 373 | .ppp_protocol = htons(LCP_PROTOCOL), 374 | }, 375 | .ppp_hdr = (ppp_header_t) { 376 | .code = CONFIG_NAK, 377 | .identifier = 0x01, 378 | .length = htons(0x0008), 379 | }, 380 | .ppp_options = (ppp_options_t *)(U8 []){ 381 | 0x01, 0x04, 0x05, 0xd0 382 | }, // MRU 383 | },{ 384 | .timer_counter = 0, 385 | .max_retransmit = 10, 386 | .ppp_payload = (ppp_payload_t) { 387 | .ppp_protocol = htons(IPCP_PROTOCOL), 388 | }, 389 | .ppp_hdr = (ppp_header_t) { 390 | .code = CONFIG_NAK, 391 | .identifier = 0x01, 392 | .length = htons(0x0010), 393 | }, 394 | .ppp_options = (ppp_options_t *)(U8 []){ 395 | 0xc0, 0xa8, 0xc8, 0xfe, 0x81, 0x06, 0xc0, 0xa8, 0x0a, 0x01 396 | }, // IP and Primary DNS 397 | },}, 398 | .user_num = 1, 399 | .vlan = 2, 400 | .PPP_dst_mac = (struct rte_ether_addr){ 401 | .addr_bytes = {0x74, 0x4d, 0x28, 0x8d, 0x00, 0x31}, 402 | }, 403 | .session_id = htons(0x000a), 404 | .cp = 0, 405 | .eth_hdr = (struct rte_ether_hdr) { 406 | .ether_type = htons(VLAN), 407 | }, 408 | .vlan_header = (vlan_header_t) { 409 | .tci_union.tci_value = htons(0002), 410 | .next_proto = htons(ETH_P_PPP_SES), 411 | }, 412 | .pppoe_header = (pppoe_header_t) { 413 | .code = 0, 414 | .ver_type = 0x11, 415 | .session_id = htons(0x000a), 416 | .length = htons(0x000a), 417 | }, 418 | }; 419 | 420 | char pkt_lcp_1[] = {/* mac */0x74, 0x4d, 0x28, 0x8d, 0x00, 0x31, 0x9c, 0x69, 0xb4, 421 | 0x61, 0x16, 0xdd, 0x81, 0x00, /* vlan */0x00, 0x02, 0x88, 0x64, /* pppoe hdr */ 422 | 0x11, 0x00, 0x00, 0x0a, 0x00, 0x0a, /* ppp protocol */0xc0, 0x21, /* ppp hdr*/ 423 | 0x04, 0x01, 0x00, 0x08, /* ppp option */0x03, 0x04, 0xc0, 0x23}; 424 | char pkt_ipcp_1[] = {/* mac */0x74, 0x4d, 0x28, 0x8d, 0x00, 0x31, 0x9c, 0x69, 0xb4, 425 | 0x61, 0x16, 0xdd, 0x81, 0x00, /* vlan */0x00, 0x02, 0x88, 0x64, /* pppoe hdr */ 426 | 0x11, 0x00, 0x00, 0x0a, 0x00, 0x0c, /* ppp protocol */0x80, 0x21, /* ppp hdr*/ 427 | 0x04, 0x01, 0x00, 0x0a, /* ppp option */0x83, 0x06, 0x00, 0x00, 0x00, 0x00}; 428 | char pkt_lcp_2[] = {/* mac */0x74, 0x4d, 0x28, 0x8d, 0x00, 0x31, 0x9c, 0x69, 0xb4, 429 | 0x61, 0x16, 0xdd, 0x81, 0x00, /* vlan */0x00, 0x02, 0x88, 0x64, /* pppoe hdr */ 430 | 0x11, 0x00, 0x00, 0x0a, 0x00, 0x0a, /* ppp protocol */0xc0, 0x21, /* ppp hdr*/ 431 | 0x03, 0x01, 0x00, 0x08, /* ppp option */0x01, 0x04, 0x05, 0xd0}; 432 | char pkt_ipcp_2[] = {/* mac */0x74, 0x4d, 0x28, 0x8d, 0x00, 0x31, 0x9c, 0x69, 0xb4, 433 | 0x61, 0x16, 0xdd, 0x81, 0x00, /* vlan */0x00, 0x02, 0x88, 0x64, /* pppoe hdr */ 434 | 0x11, 0x00, 0x00, 0x0a, 0x00, 0x10, /* ppp protocol */0x80, 0x21, /* ppp hdr*/ 435 | 0x03, 0x01, 0x00, 0x10, /* ppp option */0xc0, 0xa8, 0xc8, 0xfe, 0x81, 0x06, 0xc0, 436 | 0xa8, 0x0a, 0x01}; 437 | 438 | /* test LCP */ 439 | build_config_nak_rej(buffer, &mulen, &s_ppp_ccb_1); 440 | assert(mulen == sizeof(pkt_lcp_1)); 441 | assert(memcmp(buffer, pkt_lcp_1, sizeof(pkt_lcp_1)) == 0); 442 | 443 | /* test IPCP */ 444 | s_ppp_ccb_1.cp = 1; 445 | s_ppp_ccb_1.pppoe_header.length = htons(0x000c); 446 | memset(buffer, 0, sizeof(buffer)); 447 | build_config_nak_rej(buffer, &mulen, &s_ppp_ccb_1); 448 | assert(mulen == sizeof(pkt_ipcp_1)); 449 | assert(memcmp(buffer, pkt_ipcp_1, sizeof(pkt_ipcp_1)) == 0); 450 | 451 | s_ppp_ccb_2.cp = 0; 452 | memset(buffer, 0, sizeof(buffer)); 453 | build_config_nak_rej(buffer, &mulen, &s_ppp_ccb_2); 454 | assert(mulen == sizeof(pkt_lcp_2)); 455 | assert(memcmp(buffer, pkt_lcp_2, sizeof(pkt_lcp_2)) == 0); 456 | 457 | s_ppp_ccb_2.cp = 1; 458 | s_ppp_ccb_2.pppoe_header.length = htons(0x0010); 459 | memset(buffer, 0, sizeof(buffer)); 460 | build_config_nak_rej(buffer, &mulen, &s_ppp_ccb_2); 461 | assert(mulen == sizeof(pkt_ipcp_2)); 462 | assert(memcmp(buffer, pkt_ipcp_2, sizeof(pkt_ipcp_2)) == 0); 463 | } 464 | 465 | void test_build_terminate_ack() 466 | { 467 | U8 buffer[80] = { 0 }; 468 | U16 mulen = 0; 469 | 470 | PPP_INFO_t s_ppp_ccb_1 = { 471 | .ppp_phase = {{ 472 | .timer_counter = 0, 473 | .max_retransmit = 10, 474 | .ppp_payload = (ppp_payload_t) { 475 | .ppp_protocol = htons(LCP_PROTOCOL), 476 | }, 477 | .ppp_hdr = (ppp_header_t) { 478 | .code = TERMIN_REQUEST, 479 | .identifier = 0x01, 480 | .length = htons(0x0012), 481 | }, 482 | /* this field is not used, we juts leave this here to make sure it won't 483 | be inserted into terminate ack packet */ 484 | .ppp_options = (ppp_options_t *)(U8 []){ 485 | 0x03, 0x04, 0xc0, 0x23, 0x01, 0x04, 0x05, 0xd0, 0x05, 0x06, 0x01, 0x02, 0x03, 0x04 486 | }, // MRU, AUTH, MAGIC NUMBER 487 | },{ 488 | .timer_counter = 0, 489 | .max_retransmit = 10, 490 | .ppp_payload = (ppp_payload_t) { 491 | .ppp_protocol = htons(IPCP_PROTOCOL), 492 | }, 493 | .ppp_hdr = (ppp_header_t) { 494 | .code = CONFIG_REQUEST, 495 | .identifier = 0x01, 496 | .length = htons(0x000a), 497 | }, 498 | /* this field is not used, we juts leave this here to make sure it won't 499 | be inserted into terminate ack packet */ 500 | .ppp_options = (ppp_options_t *)(U8 []){ 501 | 0x03, 0x06, 0xc0, 0xa8, 0xc8, 0x01 502 | }, // IP_ADDRESS 503 | },}, 504 | .user_num = 1, 505 | .vlan = 2, 506 | .PPP_dst_mac = (struct rte_ether_addr){ 507 | .addr_bytes = {0x74, 0x4d, 0x28, 0x8d, 0x00, 0x31}, 508 | }, 509 | .session_id = htons(0x000a), 510 | .cp = 0, 511 | .eth_hdr = (struct rte_ether_hdr) { 512 | .ether_type = htons(VLAN), 513 | }, 514 | .vlan_header = (vlan_header_t) { 515 | .tci_union.tci_value = htons(0002), 516 | .next_proto = htons(ETH_P_PPP_SES), 517 | }, 518 | .pppoe_header = (pppoe_header_t) { 519 | .code = 0, 520 | .ver_type = 0x11, 521 | .session_id = htons(0x000a), 522 | .length = htons(0x0014), 523 | }, 524 | }; 525 | 526 | char pkt_lcp[] = {/* mac */0x74, 0x4d, 0x28, 0x8d, 0x00, 0x31, 0x9c, 0x69, 0xb4, 527 | 0x61, 0x16, 0xdd, 0x81, 0x00, /* vlan */0x00, 0x02, 0x88, 0x64, /* pppoe hdr */ 528 | 0x11, 0x00, 0x00, 0x0a, 0x00, 0x06, /* ppp protocol */0xc0, 0x21, /* ppp hdr*/ 529 | 0x06, 0x01, 0x00, 0x04}; 530 | char pkt_ipcp[] = {/* mac */0x74, 0x4d, 0x28, 0x8d, 0x00, 0x31, 0x9c, 0x69, 0xb4, 531 | 0x61, 0x16, 0xdd, 0x81, 0x00, /* vlan */0x00, 0x02, 0x88, 0x64, /* pppoe hdr */ 532 | 0x11, 0x00, 0x00, 0x0a, 0x00, 0x06, /* ppp protocol */0x80, 0x21, /* ppp hdr*/ 533 | 0x06, 0x01, 0x00, 0x04}; 534 | 535 | /* test LCP */ 536 | build_terminate_ack(buffer, &mulen, &s_ppp_ccb_1); 537 | assert(mulen == sizeof(pkt_lcp)); 538 | assert(memcmp(buffer, pkt_lcp, sizeof(pkt_lcp)) == 0); 539 | 540 | memset(buffer, 0, sizeof(buffer)); 541 | /* test IPCP */ 542 | s_ppp_ccb_1.cp = 1; 543 | build_terminate_ack(buffer, &mulen, &s_ppp_ccb_1); 544 | assert(mulen == sizeof(pkt_ipcp)); 545 | assert(memcmp(buffer, pkt_ipcp, sizeof(pkt_ipcp)) == 0); 546 | } 547 | 548 | void test_build_echo_reply() 549 | { 550 | U8 buffer[80] = { 0 }; 551 | U16 mulen = 0; 552 | 553 | PPP_INFO_t s_ppp_ccb_1 = { 554 | .ppp_phase = {{ 555 | .timer_counter = 0, 556 | .max_retransmit = 10, 557 | .ppp_payload = (ppp_payload_t) { 558 | .ppp_protocol = htons(LCP_PROTOCOL), 559 | }, 560 | .ppp_hdr = (ppp_header_t) { 561 | .code = CONFIG_REQUEST, 562 | .identifier = 0x01, 563 | .length = htons(0x0008), 564 | }, 565 | .ppp_options = (ppp_options_t *)(U8 []){ 566 | 0x05, 0x06, 0x07, 0x08 567 | }, // echo requester's magic number 568 | },{},}, 569 | .user_num = 1, 570 | .vlan = 2, 571 | .PPP_dst_mac = (struct rte_ether_addr){ 572 | .addr_bytes = {0x74, 0x4d, 0x28, 0x8d, 0x00, 0x31}, 573 | }, 574 | .session_id = htons(0x000a), 575 | .cp = 0, 576 | .magic_num = htonl(0x01020304), 577 | .eth_hdr = (struct rte_ether_hdr) { 578 | .ether_type = htons(VLAN), 579 | }, 580 | .vlan_header = (vlan_header_t) { 581 | .tci_union.tci_value = htons(0002), 582 | .next_proto = htons(ETH_P_PPP_SES), 583 | }, 584 | .pppoe_header = (pppoe_header_t) { 585 | .code = 0, 586 | .ver_type = 0x11, 587 | .session_id = htons(0x000a), 588 | .length = htons(0x0014), 589 | }, 590 | }; 591 | 592 | char pkt_lcp_1[] = {/* mac */0x74, 0x4d, 0x28, 0x8d, 0x00, 0x31, 0x9c, 0x69, 0xb4, 593 | 0x61, 0x16, 0xdd, 0x81, 0x00, /* vlan */0x00, 0x02, 0x88, 0x64, /* pppoe hdr */ 594 | 0x11, 0x00, 0x00, 0x0a, 0x00, 0x0a, /* ppp protocol */0xc0, 0x21, /* ppp hdr*/ 595 | 0x0a, 0x01, 0x00, 0x08, /* magic number */0x01, 0x02, 0x03, 0x04}; 596 | 597 | build_echo_reply(buffer, &mulen, &s_ppp_ccb_1); 598 | assert(mulen == sizeof(pkt_lcp_1)); 599 | assert(memcmp(buffer, pkt_lcp_1, sizeof(pkt_lcp_1)) == 0); 600 | 601 | char pkt_lcp_2[] = {/* mac */0x74, 0x4d, 0x28, 0x8d, 0x00, 0x31, 0x9c, 0x69, 0xb4, 602 | 0x61, 0x16, 0xdd, 0x81, 0x00, /* vlan */0x00, 0x02, 0x88, 0x64, /* pppoe hdr */ 603 | 0x11, 0x00, 0x00, 0x0a, 0x00, 0x0e, /* ppp protocol */0xc0, 0x21, /* ppp hdr*/ 604 | 0x0a, 0x01, 0x00, 0x0c, /* magic number */0x01, 0x02, 0x03, 0x04, /* echo 605 | requester's magic number */0x05, 0x06, 0x07, 0x08}; 606 | s_ppp_ccb_1.ppp_phase[0].ppp_hdr.length = htons(ntohs(s_ppp_ccb_1.ppp_phase[0].ppp_hdr.length) + 4); 607 | 608 | build_echo_reply(buffer, &mulen, &s_ppp_ccb_1); 609 | assert(mulen == sizeof(pkt_lcp_2)); 610 | assert(memcmp(buffer, pkt_lcp_2, sizeof(pkt_lcp_2)) == 0); 611 | } 612 | 613 | void test_build_auth_request_pap() 614 | { 615 | U8 buffer[80] = { 0 }; 616 | U16 mulen = 0; 617 | 618 | PPP_INFO_t s_ppp_ccb_1 = { 619 | .ppp_phase = {{ 620 | .timer_counter = 0, 621 | .max_retransmit = 10, 622 | .ppp_payload = (ppp_payload_t) { 623 | .ppp_protocol = htons(LCP_PROTOCOL), 624 | }, 625 | .ppp_hdr = (ppp_header_t) { 626 | .code = CONFIG_REQUEST, 627 | .identifier = 0x01, 628 | .length = htons(0x0000), 629 | }, 630 | },{},}, 631 | .user_num = 1, 632 | .vlan = 2, 633 | .PPP_dst_mac = (struct rte_ether_addr){ 634 | .addr_bytes = {0x74, 0x4d, 0x28, 0x8d, 0x00, 0x31}, 635 | }, 636 | .session_id = htons(0x000a), 637 | .cp = 0, 638 | .magic_num = htonl(0x01020304), 639 | .ppp_user_id = (U8 *)"asdf", // 0x61, 0x73, 0x64, 0x66 640 | .ppp_passwd = (U8 *)"zxcv", // 0x7a, 0x78, 0x63, 0x76 641 | .identifier = 0xfe, 642 | .eth_hdr = (struct rte_ether_hdr) { 643 | .ether_type = htons(VLAN), 644 | }, 645 | .vlan_header = (vlan_header_t) { 646 | .tci_union.tci_value = htons(0002), 647 | .next_proto = htons(ETH_P_PPP_SES), 648 | }, 649 | .pppoe_header = (pppoe_header_t) { 650 | .code = 0, 651 | .ver_type = 0x11, 652 | .session_id = htons(0x000a), 653 | .length = htons(0x0000), 654 | }, 655 | }; 656 | 657 | char pkt_lcp_1[] = {/* mac */0x74, 0x4d, 0x28, 0x8d, 0x00, 0x31, 0x9c, 0x69, 0xb4, 658 | 0x61, 0x16, 0xdd, 0x81, 0x00, /* vlan */0x00, 0x02, 0x88, 0x64, /* pppoe hdr */ 659 | 0x11, 0x00, 0x00, 0x0a, 0x00, 0x10, /* ppp protocol */0xc0, 0x23, /* ppp hdr*/ 660 | 0x01, 0xfe, 0x00, 0x0e, /* pap user */0x04, 0x61, 0x73, 0x64, 0x66, /* pap passwd */ 661 | 0x04, 0x7a, 0x78, 0x63, 0x76}; 662 | 663 | build_auth_request_pap(buffer, &mulen, &s_ppp_ccb_1); 664 | assert(mulen == sizeof(pkt_lcp_1)); 665 | assert(memcmp(buffer, pkt_lcp_1, sizeof(pkt_lcp_1)) == 0); 666 | 667 | char pkt_lcp_2[] = {/* mac */0x74, 0x4d, 0x28, 0x8d, 0x00, 0x31, 0x9c, 0x69, 0xb4, 668 | 0x61, 0x16, 0xdd, 0x81, 0x00, /* vlan */0x00, 0x02, 0x88, 0x64, /* pppoe hdr */ 669 | 0x11, 0x00, 0x00, 0x0a, 0x00, 0x20, /* ppp protocol */0xc0, 0x23, /* ppp hdr*/ 670 | 0x01, 0xfe, 0x00, 0x1e, /* pap user */0x08, 0x31, 0x71, 0x61, 0x7a, 0x32, 0x77, 671 | 0x73, 0x78, /* pap passwd */0x10, 0x33, 0x65, 0x64, 0x63, 0x34, 0x72, 0x66, 0x76, 672 | 0x35, 0x74, 0x67, 0x62, 0x36, 0x79, 0x68, 0x6e}; 673 | s_ppp_ccb_1.ppp_user_id = (U8 *)"1qaz2wsx"; // 0x31, 0x71, 0x61, 0x7a, 0x32, 0x77, 0x73, 0x78 674 | s_ppp_ccb_1.ppp_passwd = (U8 *)"3edc4rfv5tgb6yhn"; // 0x33, 0x65, 0x64, 0x63, 0x34, 0x72, 0x66, 0x76, 0x35, 0x74, 0x67, 0x62, 0x36, 0x79, 0x68, 0x6e 675 | 676 | build_auth_request_pap(buffer, &mulen, &s_ppp_ccb_1); 677 | assert(mulen == sizeof(pkt_lcp_2)); 678 | assert(memcmp(buffer, pkt_lcp_2, sizeof(pkt_lcp_2)) == 0); 679 | } 680 | 681 | void test_build_auth_ack_pap() 682 | { 683 | U8 buffer[80] = { 0 }; 684 | U16 mulen = 0; 685 | 686 | PPP_INFO_t s_ppp_ccb_1 = { 687 | .ppp_phase = {{ 688 | .timer_counter = 0, 689 | .max_retransmit = 10, 690 | .ppp_payload = (ppp_payload_t) { 691 | .ppp_protocol = htons(LCP_PROTOCOL), 692 | }, 693 | .ppp_hdr = (ppp_header_t) { 694 | .code = CONFIG_REQUEST, 695 | .identifier = 0x01, 696 | .length = htons(0x0000), 697 | }, 698 | },{},}, 699 | .user_num = 1, 700 | .vlan = 2, 701 | .PPP_dst_mac = (struct rte_ether_addr){ 702 | .addr_bytes = {0x74, 0x4d, 0x28, 0x8d, 0x00, 0x31}, 703 | }, 704 | .session_id = htons(0x000a), 705 | .cp = 0, 706 | .magic_num = htonl(0x01020304), 707 | .ppp_user_id = (U8 *)"asdf", // 0x61, 0x73, 0x64, 0x66 708 | .ppp_passwd = (U8 *)"zxcv", // 0x7a, 0x78, 0x63, 0x76 709 | .identifier = 0xfe, 710 | .eth_hdr = (struct rte_ether_hdr) { 711 | .ether_type = htons(VLAN), 712 | }, 713 | .vlan_header = (vlan_header_t) { 714 | .tci_union.tci_value = htons(0002), 715 | .next_proto = htons(ETH_P_PPP_SES), 716 | }, 717 | .pppoe_header = (pppoe_header_t) { 718 | .code = 0, 719 | .ver_type = 0x11, 720 | .session_id = htons(0x000a), 721 | .length = htons(0x0000), 722 | }, 723 | }; 724 | 725 | char pkt_lcp_1[] = {/* mac */0x74, 0x4d, 0x28, 0x8d, 0x00, 0x31, 0x9c, 0x69, 0xb4, 726 | 0x61, 0x16, 0xdd, 0x81, 0x00, /* vlan */0x00, 0x02, 0x88, 0x64, /* pppoe hdr */ 727 | 0x11, 0x00, 0x00, 0x0a, 0x00, 0x0f, /* ppp protocol */0xc0, 0x23, /* ppp hdr*/ 728 | 0x02, 0xfe, 0x00, 0x0d, /* Login ok */0x08, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x20, 729 | 0x6f, 0x6b}; 730 | 731 | build_auth_ack_pap(buffer, &mulen, &s_ppp_ccb_1); 732 | assert(mulen == sizeof(pkt_lcp_1)); 733 | assert(memcmp(buffer, pkt_lcp_1, sizeof(pkt_lcp_1)) == 0); 734 | } 735 | --------------------------------------------------------------------------------