vpp插件DHCP client源码分析

vpp插件DHCP client源码

1、使用dhcp_api.c中的函数添加dhcp client

源码vpp/src/pluggings/dhcp/dhcp_api.c

在VPP(Vector Packet Processing)中配置DHCP客户端涉及一系列步骤,以下是大致的代码流程:

  1. 包含必要的头文件: 在代码中包含必要的VPP头文件,这些头文件包含了配置DHCP客户端所需的结构和函数。

    cCopy code#include <vlib/vlib.h>
    #include <vnet/ip/ip.h>
    #include <vnet/dhcp/dhcp_client_common.h>
    
  2. 创建配置结构体: 定义一个用于配置DHCP客户端的结构体vl_api_dhcp_client_config_t

    struct codevl_api_dhcp_client_config_t dhcp_client_config = {
        .client_index = ...,
        .hostname = "...",
        // 设置其他配置参数
    };
    
  3. 发送消息配置DHCP客户端: 使用VPP提供的API函数将配置信息发送到VPP中。

    static void vl_api_dhcp_client_config_t_handler
      (vl_api_dhcp_client_config_t * mp);
    
  4. 处理配置消息: 有一个处理接收到的DHCP客户端配置消息的函数。在这个函数中,将会解析接收到的配置信息,并将其应用到DHCP客户端。

    // 解析配置信息并应用到DHCP客户端
    // config->client_index, config->hostname 等是消息中的配置参数
    // 应用配置到DHCP客户端
    static void vl_api_dhcp_client_config_t_handler(vl_api_dhcp_client_config_t * mp)
    {
      vlib_main_t *vm = vlib_get_main ();
      vl_api_dhcp_client_config_reply_t *rmp;
      u32 sw_if_index;
      ip_dscp_t dscp;
      int rv = 0;
    
      VALIDATE_SW_IF_INDEX (&(mp->client));
    
      sw_if_index = ntohl (mp->client.sw_if_index);
      dscp = ip_dscp_decode (mp->client.dscp);
    
      rv = dhcp_client_config (mp->is_add,
    			   mp->client_index,
    			   vm,
    			   sw_if_index,
    			   mp->client.hostname,
    			   mp->client.id,
    			   (mp->client.want_dhcp_event ?
    			    dhcp_compl_event_callback :
    			    NULL),
    			   mp->client.set_broadcast_flag,
    			   dscp, mp->client.pid);
    
      BAD_SW_IF_INDEX_LABEL;
      REPLY_MACRO (VL_API_DHCP_CLIENT_CONFIG_REPLY);
    }
    

vl_api_dhcp_client_config_t是用于配置DHCP客户端的数据结构,而_handlervl_api_dhcp_client_config_t_handler则表示一个用于处理此配置结构的函数。这个函数负责接收配置信息、验证参数、将配置应用到系统中等操作。具体函数的实现可能会根据不同的代码库、框架或项目而有所不同,因此建议查阅相关的VPP文档、代码注释或源代码,以便获得关于vl_api_dhcp_client_config_tvl_api_dhcp_client_config_t_handler的详细信息和实际用法。

2、DHCPv4 client命令行源码分析

源码vpp/src/pluggings/dhcp/client.c

(1)、初始化

初始dhcp_client_main结构体,查找ip4-lookup节点索引。

VLIB_INIT_FUNCTION (dhcp_client_init);

一般情况下,在VPP中,数据包经过一系列处理步骤,包括接收、解析、处理、转发等。ip4-lookup则是用于在路由过程中查找目的地IP地址的动作,用于确定应该将数据包发送到网络中的哪个接口或下一跳。

在本处当client发送DHCP Discover时,为了接受任何OFFER,无论是广播还是单播,都需要将 dhcp-client-detect 功能配置为输入功能,以便DHCP OFFER被发送到ip4-local节点。如果没有 dhcp-client-detect,广播的OFFER会到达255.255.255.255/32地址,单播会到达 0.0.0.0/0,这两个地址默认都会丢弃该报文,而后者可能会转发到其他地方。

dhcp-client-detect通常用于特定的数据包处理流程中,用于识别DHCP客户端的数据包。一旦识别出DHCP客户端的数据包,通常会触发特定的处理流程,可能涉及为客户端分配IP地址或处理网络配置等。但它并不直接涉及到路由决策或数据包的转发。

(2)注册添加/删除client命令模块
VLIB_CLI_COMMAND (dhcp_client_set_command, static) = {
 .path = "set dhcp client",
 .short_help = "set dhcp client [del] intfc <interface> [hostname <name>]",
 .function = dhcp_client_set_command_fn,
};
①、读取配置参数,添加或删除client
static clib_error_t * dhcp_client_set_command_fn (vlib_main_t * vm, 
	unformat_input_t * input,
	vlib_cli_command_t * cmd);

int dhcp_client_add_del (dhcp_client_add_del_args_t * a);

添加client需要先在DHCP client pool索引if,查找是否存在相同的,不存在的话,再从DHCP client pool中分配一个client并添加设备信息。

②、发送信号事件(Signal Event)给指定的处理进程(Process)
always_inline void
vlib_process_signal_event (vlib_main_t * vm,
                          uword node_index, uword type_opaque, uword data);
  • vm:VLIB 主要数据结构的指针,代表 VPP 的主要执行环境。
  • event_type:信号事件的类型,可以是自定义的事件类型。
  • event_data:携带的事件数据,根据实际需要传递。
  • process_node_index:目标处理进程的索引,指示应该将事件发送给哪个处理进程。

这个函数用于向 VPP 中的特定处理进程发送自定义的信号事件,从而触发或通知该进程执行特定的操作或任务。这种机制可以用于 VPP 中不同处理节点之间的通信、同步或协调任务。

本处注册的client 处理进程

VLIB_REGISTER_NODE (dhcp_client_process_node,static) = {
  .function = dhcp_client_process,
  .type = VLIB_NODE_TYPE_PROCESS,
  .name = "dhcp-client-process",
  .process_log2_n_stack_bytes = 16,
  .n_errors = ARRAY_LEN(dhcp_client_process_stat_strings),
  .error_strings = dhcp_client_process_stat_strings,
};
③client 处理进程函数
static uword
dhcp_client_process (vlib_main_t * vm,
	vlib_node_runtime_t * rt, vlib_frame_t * f)

dhcp_client_process循环检测DHCP client pool活跃设备根据设备状态持续时间以及设备状态发送对应数据包,包括dhcp_discover_state、dhcp_request_state、dhcp_bound_state。

static int
dhcp_discover_state (dhcp_client_main_t * dcm, dhcp_client_t * c, f64 now);

static int
dhcp_request_state (dhcp_client_main_t * dcm, dhcp_client_t * c, f64 now);

static int
dhcp_bound_state (dhcp_client_main_t * dcm, dhcp_client_t * c, f64 now);//处于“BOUND”状态的客户端可以正常地进行网络通信,它已经成功地获取了所需的网络配置信息,可以和网络中的其他设备进行通信。这个状态一般会在 DHCP 客户端成功完成租约过程后出现。主要用于续订租约、解约。

client接收到服务端的网络配置后,进行的网络配置,其中可能涉及的一些函数或模块可能包括:

  • vnet/ip/ip4.h 或 vnet/ip/ip6.h:用于 IPv4 或 IPv6 配置的相关函数。比如,ip4_set_interface_addressip6_set_interface_address 可能被用来设置接口地址。
  • vnet/ip/ip_neighbor.h:处理邻居(Neighbor)相关的函数,用于将 IP 地址与 MAC 地址关联。
  • vnet/ip/ip_source_and_port_range_check.h:用于源 IP 和端口范围检查的函数。
  • vnet/ip/ip6_neighbor.h:用于 IPv6 邻居关联的函数。
(3)注册查看client信息命令模块
VLIB_CLI_COMMAND (show_dhcp_client_command, static) = {
 .path = "show dhcp client",
 .short_help = "show dhcp client [intfc <intfc>][verbose]",
 .function = show_dhcp_client_command_fn,
};
①、读取命令参数
static clib_error_t *
show_dhcp_client_command_fn (vlib_main_t * vm,
	unformat_input_t * input,
	vlib_cli_command_t * cmd)
②、根据命令参数显示client info
static u8 *format_dhcp_client (u8 * s, va_list * va)

verbose参数显示DHCP client详细信息

(4)其它功能函数
/*
 \* dhcp_client_for_us - server-to-client callback.
 \* Called from proxy_node.c:dhcp_proxy_to_client_input().
 \* This function first decides that the packet in question is
 \* actually for the dhcp client code in case we're also acting as
 \* a dhcp proxy. Ay caramba, what a folly!
 */
int
dhcp_client_for_us (u32 bi, vlib_buffer_t * b,
	ip4_header_t * ip,
	udp_header_t * udp, dhcp_header_t * dhcp)

在 VPP(Vector Packet Processing)中,dhcp_client_for_us 是用于检查一个 DHCP(Dynamic Host Configuration Protocol)数据包是否适用于本地接口的 DHCP 客户端。

这个函数通常用于检查接收到的 DHCP 数据包是否是发送给本地接口的。在网络中,DHCP 客户端通常会发送 DHCP 请求以获取 IP 地址等配置信息。dhcp_client_for_us 函数用于验证接收到的 DHCP 数据包是否与本地接口相关。

这个函数的作用通常是检查数据包中的目标 IP 地址或其他标识,以确定 DHCP 数据包是否针对本地接口。如果是,接口将处理该 DHCP 数据包,并相应地进行后续操作,比如为本地设备获取 IP 地址和其他网络配置。

在实际使用中,dhcp_client_for_us 可能作为 VPP 中的数据包处理函数的一部分,用于筛选和处理适用于本地接口的 DHCP 数据包。

  • 24
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用VPP进行收包发包的插件示例: 1. 接收插件示例: ``` #include <vlib/vlib.h> static uword my_input_node (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { u32 n_left_from, * from, * to_next; my_input_next_t next_index; my_input_trace_t * t; vnet_main_t * vnm = vnet_get_main(); from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; next_index = node->cached_next_index; while (n_left_from > 0) { u32 n_left_to_next; vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); while (n_left_from > 0 && n_left_to_next > 0) { u32 bi0; vlib_buffer_t * b0; u32 next0; bi0 = from[0]; from += 1; n_left_from -= 1; to_next[0] = bi0; to_next += 1; n_left_to_next -= 1; b0 = vlib_get_buffer (vm, bi0); t = vlib_add_trace (vm, node, b0, sizeof (*t)); t->sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX]; next0 = MY_INPUT_NEXT_NORMAL; vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, bi0, next0); } vlib_put_next_frame (vm, node, next_index, n_left_to_next); } return frame->n_vectors; } ``` 2. 发送插件示例: ``` #include <vnet/vnet.h> #include <vnet/ip/ip.h> static u32 my_output_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { u32 n_left_from, * from; u32 n_left_to_next, * to_next; my_output_next_t next_index; u32 pkts_sent = 0; vlib_frame_t *f; u32 thread_index = vm->thread_index; from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; next_index = node->cached_next_index; while (n_left_from > 0) { u32 n_left_to_next; vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); while (n_left_from > 0 && n_left_to_next > 0) { u32 bi0; vlib_buffer_t * b0; u32 next0 = 0; u32 error0 = 0; u32 sw_if_index0; bi0 = from[0]; from += 1; n_left_from -= 1; to_next[0] = bi0; to_next += 1; n_left_to_next -= 1; b0 = vlib_get_buffer (vm, bi0); sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; vlib_buffer_advance (b0, -sizeof (ethernet_header_t)); ethernet_header_t *eth = vlib_buffer_get_current (b0); eth->type = clib_host_to_net_u16 (ETHERNET_TYPE_IP4); if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) { my_output_trace_t *tr = vlib_add_trace (vm, node, b0, sizeof (*tr)); tr->sw_if_index = sw_if_index0; tr->next_index = next0; } vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, bi0, next0); pkts_sent++; } vlib_put_next_frame (vm, node, next_index, n_left_to_next); } vlib_node_increment_counter (vm, my_output_node.index, MY_OUTPUT_ERROR_TX, pkts_sent); return frame->n_vectors; } ``` 这里仅是简单的示例,实际使用中需要根据具体需求进行修改和完善。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值