- 发布于
创建你的第一个FRRouting守护进程
系列: 编写FRRouting的守护进程
章节: (1/2)
- 创建你的第一个FRRouting守护进程
- 为你的FRRouting守护进程添加一个socket服务器
我个人写c语言写的并不多,对makefile构建系统的研究不是很透彻,所以在这里我会尽量详细的介绍一些步骤,希望能够帮助到你。
前言
演示的linux发行版为Ubuntu 22.04,FRRouting版本为10.2.1。
本片文章默认你在阅读了官方安装文档,并且能够成功 安装官方10.2.1版本的FRRouting 的基础上,进行下一步操作。
由于我之前是通过docker安装并测试的FRRouting,所以在这里我会以docker的方式来进行最终效果演示。(官方的alpine docker安装教程)
编写daemon
本文的目的是为了让你能够编写一个简单的daemon,所以我会尽量简化代码,让你能够更容易的理解。
第一步-为构建做准备
不妨将你的第一个守护进程命名为helloworld
。就像dockerd一样,这个d
代表的是daemon
。
本教程中其实并未使用到vtysh的功能,如下修改的文件简单介绍如下:
configure.ac
:用于配置是否启用一些功能,即./configure
相关的配置。Makefile.am
:用于编译构建的文件。
Configure.ac的配置
configure.ac
@@ -733,6 +733,8 @@ AC_ARG_ENABLE([babeld],
AS_HELP_STRING([--disable-babeld], [do not build babeld]))
AC_ARG_ENABLE([watchfrr],
AS_HELP_STRING([--disable-watchfrr], [do not build watchfrr]))
+AC_ARG_ENABLE([helloworld],
+ AS_HELP_STRING([--disable-helloworld], [do not build helloworld]))
AC_ARG_ENABLE([isisd],
AS_HELP_STRING([--disable-isisd], [do not build isisd]))
AC_ARG_ENABLE([pimd],
configure.ac
@@ -1877,6 +1879,11 @@ AS_IF([test "$enable_babeld" != "no"], [
AC_DEFINE([HAVE_BABELD], [1], [babeld])
])
+## HAVE_HELLOWORLD used for vtysh/vtysh.c
+AS_IF([test "$enable_helloworld" != "no"], [
+ AC_DEFINE([HAVE_HELLOWORLD], [1], [helloworld])
+])
+
AS_IF([test "$enable_isisd" != "no"], [
AC_DEFINE([HAVE_ISISD], [1], [isisd])
])
configure.ac
@@ -2802,6 +2809,7 @@ AM_CONDITIONAL([OSPFCLIENT], [test "$OSPFCLIENT" = "ospfclient"])
AM_CONDITIONAL([RIPNGD], [test "$enable_ripngd" != "no"])
AM_CONDITIONAL([BABELD], [test "$enable_babeld" != "no"])
AM_CONDITIONAL([OSPF6D], [test "$enable_ospf6d" != "no"])
+AM_CONDITIONAL([HELLOWORLD], [test "$enable_helloworld" != "no"])
AM_CONDITIONAL([ISISD], [test "$enable_isisd" != "no"])
AM_CONDITIONAL([PIMD], [test "$enable_pimd" != "no"])
AM_CONDITIONAL([PIM6D], [test "$enable_pim6d" != "no"])
Makefile.am的配置
Makefile.am
@@ -194,6 +194,7 @@ include ripngd/subdir.am
include ospfd/subdir.am
include ospf6d/subdir.am
include ospfclient/subdir.am
+include helloworld/subdir.am
include isisd/subdir.am
include nhrpd/subdir.am
include ldpd/subdir.am
Makefile.am
@@ -273,6 +274,7 @@ EXTRA_DIST += \
eigrpd/Makefile \
fpm/Makefile \
grpc/Makefile \
+ helloworld/Makefile \
isisd/Makefile \
ldpd/Makefile \
lib/Makefile \
lib/libfrr.h的配置
lib/libfrr.h
@@ -103,6 +103,9 @@ DECLARE_DLIST(log_args, struct log_arg, itm);
#define MGMTD_VTY_PORT 2623
/* Registry of daemons' port defaults */
+/* your daemon */
+#define HELLOWORLD_VTY_PORT 2624
+
enum frr_cli_mode {
FRR_CLI_CLASSIC = 0,
FRR_CLI_TRANSACTIONAL,
让frr启动项知道你的守护进程
在这之后,你需要让frr启动项知道你的守护进程
tools/etc/frr/daemons
tools/etc/frr/daemons
@@ -19,6 +19,7 @@ ospfd=no
ospf6d=no
ripd=no
ripngd=no
+helloworld=yes
isisd=no
pimd=no
pim6d=no
tools/etc/frr/daemons
@@ -46,6 +47,7 @@ ospfd_options=" -A 127.0.0.1"
ospf6d_options=" -A ::1"
ripd_options=" -A 127.0.0.1"
ripngd_options=" -A ::1"
+helloworld_options=" -A 127.0.0.1"
isisd_options=" -A 127.0.0.1"
pimd_options=" -A 127.0.0.1"
pim6d_options=" -A ::1"
tools/frrcommon.sh.in
tools/frrcommon.sh.in
@@ -36,7 +36,7 @@ FRR_DEFAULT_PROFILE="@DFLT_NAME@" # traditional / datacenter
# - keep zebra first
# - watchfrr does NOT belong in this list
-DAEMONS="zebra mgmtd bgpd ripd ripngd ospfd ospf6d isisd babeld pimd pim6d ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd vrrpd pathd"
+DAEMONS="zebra mgmtd bgpd ripd ripngd ospfd ospf6d helloworld isisd babeld pimd pim6d ldpd nhrpdeigrpd sharpd pbrd staticd bfdd fabricd vrrpd pathd"
RELOAD_SCRIPT="$D_PATH/frr-reload.py"
#
第二步-编写helloworld守护进程
首先需要在项目目录下创建文件夹 helloworld
,并在此文件夹中创建相关文件。
1. 准备构建相关文件: Makefile subdir.am .gitignore
helloworld/Makefile
all: ALWAYS
@$(MAKE) -s -C .. helloworld/helloworld
%: ALWAYS
@$(MAKE) -s -C .. helloworld/$@
Makefile:
#nothing
ALWAYS:
.PHONY: ALWAYS makefiles
.SUFFIXES:
helloworld/subdir.am
#
# helloworld
#
if HELLOWORLD
sbin_PROGRAMS += helloworld/helloworld
vtysh_daemons += helloworld
endif
helloworld_helloworld_SOURCES = \
helloworld/helloworld_main.c \
helloworld/helloworld.c \
# end
noinst_HEADERS += \
helloworld/helloworld.h \
# end
helloworld_helloworld_LDADD = lib/libfrr.la $(LIBCAP)
helloworld/.gitignore
helloworld
2. 开始编写守护进程相关代码
helloworld/helloworld.h
#ifndef _BGPMGMTD_H
#define _BGPMGMTD_H
#include "lib/libfrr.h"
#endif /* _BGPMGMTD_H */
helloworld/helloworld.c
#include "helloworld/helloworld.h"
核心代码⬇️
helloworld/helloworld_main.c
#include <zebra.h>
#include <lib/version.h>
#include "helloworld/helloworld.h"
/* Master of threads. */
struct event_loop *master;
/* 处理中断信号 */
/* signal definitions */
void sighup(void);
void sigint(void);
void sigusr1(void);
/* SIGHUP handler. */
void sighup(void)
{
zlog_info("SIGHUP received, ignoring");
return;
}
/* SIGUSR1 handler. */
void sigusr1(void)
{
zlog_rotate();
}
/* SIGINT handler. */
__attribute__((__noreturn__)) void sigint(void)
{
zlog_notice("Terminating on signal");
/* 执行在此hook中注册的函数,大多跟结束程序相关 */
/* Signalize shutdown. */
frr_early_fini();
/* 执行在此hook中注册的函数,多跟回收资源相关 */
/* Terminate and free() FRR related memory. */
frr_fini();
exit(0);
}
static struct frr_signal_t helloworld_signals[] = {
{
.signal = SIGHUP,
.handler = &sighup,
},
{
.signal = SIGUSR1,
.handler = &sigusr1,
},
{
.signal = SIGINT,
.handler = &sigint,
},
{
.signal = SIGTERM,
.handler = &sigint,
},
};
/* privileges */
static zebra_capabilities_t _caps_p[] = {ZCAP_BIND, ZCAP_NET_RAW,
ZCAP_NET_ADMIN, ZCAP_SYS_ADMIN};
struct zebra_privs_t helloworld_privs = {
#if defined(FRR_USER) && defined(FRR_GROUP)
.user = FRR_USER,
.group = FRR_GROUP,
#endif
#ifdef VTY_GROUP
.vty_group = VTY_GROUP,
#endif
.caps_p = _caps_p,
.cap_num_p = array_size(_caps_p),
.cap_num_i = 0,
};
static struct frr_daemon_info helloworld_di;
FRR_DAEMON_INFO(helloworld, BGPMGMTD,
.vty_port = HELLOWORLD_VTY_PORT,
.proghelp = "Implementation of your first helloworld Daemon.",
.signals = helloworld_signals,
.n_signals = array_size(helloworld_signals),
.privs = &helloworld_privs,
);
int main(int argc, char **argv)
{
int opt;
frr_preinit(&helloworld_di, argc, argv);
/* 处理参数,重要不可删除 */
while (true) {
opt = frr_getopt(argc, argv, NULL);
if (opt == EOF)
break;
}
/* Initialize FRR infrastructure. */
master = frr_init();
frr_config_fork();
/* not the recommended way to log, you should use zlog instead of fprintf */
fprintf(stdout, "helloworld! your first deamon helloworld has started.\n");
/* 在frr事件循环中添加此守护进程 */
frr_run(master);
/* Not reached. */
return 0;
}
编译运行
可选项(主机make来查看是否有编译错误)
根据官网安装好libyang2后,执行如下命令进行构建环境的准备以及编译构建,可以不需要安装至主机
#/bin/bash
./bootstrap.sh
./configure \
--prefix=/usr \
--includedir=\${prefix}/include \
--bindir=\${prefix}/bin \
--sbindir=\${prefix}/lib/frr \
--libdir=\${prefix}/lib/frr \
--libexecdir=\${prefix}/lib/frr \
--sysconfdir=/etc \
--localstatedir=/var \
--with-moduledir=\${prefix}/lib/frr/modules \
--enable-configfile-mask=0640 \
--enable-logfile-mask=0640 \
--enable-snmp=agentx \
--enable-multipath=64 \
--enable-user=frr \
--enable-group=frr \
--enable-vty-group=frrvty \
--with-pkg-git-version \
--with-pkg-extra-version=-MyOwnFRRVersion
make -j$(nproc)
docker构建
在此之前,确保你执行了这一步骤 (让frr启动项知道你的守护进程)
构建镜像
docker build -t frr-helloworld -f docker/alpine/Dockerfile .
运行容器
docker run -it --rm --name frr-helloworld \
--privileged \
-v ./tools/etc/frr/daemons:/etc/frr/daemons \
frr-helloworld
运行效果

分享