vpp中plugin的api编程(2) - VPE vs. Plugin Messages id

msgid是唯一识别api函数的标识,但是在使用的时候,plugin与vpe有一些区别,需要注意。
在代码中以VL_API_XXX来显示,具体的值是在编译的时候才确定的。

VPE注册时,使用的是全局宏,模块中第一个msg id不是0

static clib_error_t *
ipsec_api_hookup (vlib_main_t * vm)
{
  api_main_t *am = &api_main;

#define _(N,n)                                                      vl_msg_api_set_handlers(VL_API_##N, #n,                                                vl_api_##n##_t_handler,                                         vl_noop_handler,                                                vl_api_##n##_t_endian,                                          vl_api_##n##_t_print,                                           sizeof(vl_api_##n##_t), 1);
  foreach_vpe_api_msg;
#undef _

  /*
   * Set up the (msg_name, crc, message-id) table
   */
  setup_message_id_table (am);

  return 0;
}

plugin注册时,使用的是基址+偏移,模块中的第一个msg_id是0,必须加上基址才能使用。

static
void acl_vat_api_hookup (vat_main_t *vam)
{
    acl_test_main_t * sm = &acl_test_main;
    /* Hook up handlers for replies from the data plane plug-in */
#define _(N,n)                                                      vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base),                                #n,                                                             vl_api_##n##_t_handler,                                         vl_noop_handler,                                                vl_api_##n##_t_endian,                                          vl_api_##n##_t_print,                                           sizeof(vl_api_##n##_t), 1);
    foreach_vpe_api_reply_msg;
#undef _

}

为什么会有这样的区别,我们来看一下。

plugin的message id

生成偏移

plugin是通过头文件包含的方式生成了偏移,即 VL_API_XXXX
以acl为例
是通过这3个.h来实现的。

acl_msg_enum.h  -- 定义枚举结构,每个模块都是从0开始的
acl_all_api_h.h   -- 所有acl api相关的.h文件都放在这里
acl.api.h      -- acl使用的VL_API_XXX按顺序排布

  • acl_msg_enum.h
    创建了枚举结构,包含了acl_all_api_h.h

    
    20 #define vl_msg_id(n,h) n,
    21 typedef enum {
    22 #include <acl/acl_all_api_h.h>
    23     /* We‘ll want to know how many messages IDs we need... */
    24     VL_MSG_FIRST_AVAILABLE,
    25 } vl_msg_id_t;
    26 #undef vl_msg_id
+ acl_all_api_h.h
所有acl api有关头文件都放在这里,统一管理
包含了acl.api.h
```c

 16 #include <acl/acl.api.h>
 17
 18 #ifdef vl_printfun
 19 #include <acl/manual_fns.h>
 20 #endif
  • acl.api.h
    由acl.api生成的文件,按顺序排布了VL_API_XXX

    
    18 /****** Message ID / handler enum ******/
    19
    20 #ifdef vl_msg_id
    21 vl_msg_id(VL_API_ACL_ENABLE_CONFIG, vl_api_acl_enable_config_t_handler)
    22 vl_msg_id(VL_API_ACL_ENABLE_CONFIG_REPLY, vl_api_acl_enable_config_reply_t_handler)
    23 vl_msg_id(VL_API_ACL_PLUGIN_GET_VERSION, vl_api_acl_plugin_get_version_t_handler)
    24 vl_msg_id(VL_API_ACL_PLUGIN_GET_VERSION_REPLY, vl_api_acl_plugin_get_version_reply_t_handler)
    25 vl_msg_id(VL_API_ACL_PLUGIN_CONTROL_PING, vl_api_acl_plugin_control_ping_t_handler)
    26 vl_msg_id(VL_API_ACL_PLUGIN_CONTROL_PING_REPLY, vl_api_acl_plugin_control_ping_reply_t_handler)
    27 /* typeonly: acl_rule */
    28 /* typeonly: macip_acl_rule */
    29 vl_msg_id(VL_API_ACL_ADD_REPLACE, vl_api_acl_add_replace_t_handler)
    30 vl_msg_id(VL_API_ACL_ADD_REPLACE_REPLY, vl_api_acl_add_replace_reply_t_handler)
    31 vl_msg_id(VL_API_ACL_DEL, vl_api_acl_del_t_handler)
    32 vl_msg_id(VL_API_ACL_DEL_REPLY, vl_api_acl_del_reply_t_handler)
    33 vl_msg_id(VL_API_ACL_INTERFACE_ADD_DEL, vl_api_acl_interface_add_del_t_handler)
    34 vl_msg_id(VL_API_ACL_INTERFACE_ADD_DEL_REPLY, vl_api_acl_interface_add_del_reply_t_handler)
    35 vl_msg_id(VL_API_ACL_INTERFACE_SET_ACL_LIST, vl_api_acl_interface_set_acl_list_t_handler)
    ...
    51 #endif
 这样就生成了模块内api函数的偏移。

### 获得基址
调用vl_msg_api_get_msg_ids函数获得
```c
u16
vl_msg_api_get_msg_ids (const char *name, int n)
{
  api_main_t *am = &api_main;
  u8 *name_copy;
  vl_api_msg_range_t *rp;
  uword *p;
  u16 rv;

  if (am->msg_range_by_name == 0)
    am->msg_range_by_name = hash_create_string (0, sizeof (uword));

  //获得干净的模块名(无数数字)
  name_copy = format (0, "%s%c", name, 0);

  //查看是否注册过
  p = hash_get_mem (am->msg_range_by_name, name_copy);
  if (p)
    {
      clib_warning ("WARNING: duplicate message range registration for ‘%s‘",
            name_copy);
      vec_free (name_copy);
      return ((u16) ~ 0);
    }

  //msg号的范围判断
  if (n < 0 || n > 1024)
    {
      clib_warning
    ("WARNING: bad number of message-IDs (%d) requested by ‘%s‘",
     n, name_copy);
      vec_free (name_copy);
      return ((u16) ~ 0);
    }

  //am->msg_ranges这个结构很重要,管理了所有的msg的范围
  //获得rp
  vec_add2 (am->msg_ranges, rp, 1);

  //获取模块的msg_id。这个id是用全局的first_available_msg_id的
  //每次加载一个模块后,就会增加响应的个数,这样就把所有的msg_id串起来了。
  rv = rp->first_msg_id = am->first_available_msg_id;
  //增加全局msg_id个数,供下个模块使用
  am->first_available_msg_id += n;
  rp->last_msg_id = am->first_available_msg_id - 1;
  rp->name = name_copy;

  //以名字为key,存入。clinet会用这个名字请求index
  hash_set_mem (am->msg_range_by_name, name_copy, rp - am->msg_ranges);

  return rv;
}

使用

VPE下的message id

生成全局msg_id

VPE也是通过头文件包含的方式生成的
每个模块内部的第一个msg_id不是从0排布的,而是全局的,因为包含了所有的头文件

以ipsec为例
是通过这3个.h来实现的。
vnet_msg_enum.h  -- 定义枚举结构
vnet_all_api_h.h   -- 所有VPE api相关的.h文件都放在这里
ipsec.api.h      -- ipsec使用的VL_API_XXX按顺序排布

  • vnet_msg_enum.h
    定义的枚举结构,包含了vnet_all_api_h.h

    
    18 #include <vppinfra/byte_order.h>
    19
    20 #define vl_msg_id(n,h) n,
    21 typedef enum
    22 {
    23   VL_ILLEGAL_MESSAGE_ID = 0,
    24 #include <vnet/vnet_all_api_h.h>
    25   VL_MSG_FIRST_AVAILABLE,
    26 } vl_msg_id_t;
    27 #undef vl_msg_id
    28
    29 #endif /* included_vnet_msg_enum_h */

+ vnet_all_api_h.h
所有vnet的模块都在里面

```c
28 #ifndef included_from_layer_3
 29 #include <vlibmemory/vl_memory_api_h.h>
 30 #endif /* included_from_layer_3 */
 31
 32 #include <vnet/devices/af_packet/af_packet.api.h>
 33 #include <vnet/devices/netmap/netmap.api.h>
 34 #include <vnet/devices/virtio/vhost_user.api.h>
 35 #include <vnet/gre/gre.api.h>
 36 #include <vnet/interface.api.h>
 37 #include <vnet/map/map.api.h>
 38 #include <vnet/l2/l2.api.h>
 39 #include <vnet/l2tp/l2tp.api.h>
 40 #include <vnet/span/span.api.h>
 41 #include <vnet/ip/ip.api.h>
 42 #include <vnet/unix/tap.api.h>
 43 #include <vnet/vxlan/vxlan.api.h>
 44 #include <vnet/lldp/lldp.api.h>
 45 #include <vnet/vxlan-gpe/vxlan_gpe.api.h>
 46 #include <vnet/bfd/bfd.api.h>
 47 #include <vnet/ipsec/ipsec.api.h>
 48 #include <vnet/ipsec-gre/ipsec_gre.api.h>
  • ipsec.api.h
    ipsec所需的msg id

    18 /****** Message ID / handler enum ******/
    19
    20 #ifdef vl_msg_id
    21 vl_msg_id(VL_API_IPSEC_SPD_ADD_DEL, vl_api_ipsec_spd_add_del_t_handler)
    22 vl_msg_id(VL_API_IPSEC_SPD_ADD_DEL_REPLY, vl_api_ipsec_spd_add_del_reply_t_handler)
    23 vl_msg_id(VL_API_IPSEC_INTERFACE_ADD_DEL_SPD, vl_api_ipsec_interface_add_del_spd_t_handler)
    24 vl_msg_id(VL_API_IPSEC_INTERFACE_ADD_DEL_SPD_REPLY, vl_api_ipsec_interface_add_del_spd_reply_t_handler)
    25 vl_msg_id(VL_API_IPSEC_SPD_ADD_DEL_ENTRY, vl_api_ipsec_spd_add_del_entry_t_handler)
    26 vl_msg_id(VL_API_IPSEC_SPD_ADD_DEL_ENTRY_REPLY, vl_api_ipsec_spd_add_del_entry_reply_t_handler)
    27 vl_msg_id(VL_API_IPSEC_SAD_ADD_DEL_ENTRY, vl_api_ipsec_sad_add_del_entry_t_handler)
    28 vl_msg_id(VL_API_IPSEC_SAD_ADD_DEL_ENTRY_REPLY, vl_api_ipsec_sad_add_del_entry_reply_t_handler)
    29 vl_msg_id(VL_API_IPSEC_SA_SET_KEY, vl_api_ipsec_sa_set_key_t_handler)
    30 vl_msg_id(VL_API_IPSEC_SA_SET_KEY_REPLY, vl_api_ipsec_sa_set_key_reply_t_handler)
    31 vl_msg_id(VL_API_IKEV2_PROFILE_ADD_DEL, vl_api_ikev2_profile_add_del_t_handler)
    32 vl_msg_id(VL_API_IKEV2_PROFILE_ADD_DEL_REPLY, vl_api_ikev2_profile_add_del_reply_t_handler)

    这样所有VPE有关全局的msg id就创建好了

原文地址:http://blog.51cto.com/zhangchixiang/2128871

时间: 2024-11-14 12:49:38

vpp中plugin的api编程(2) - VPE vs. Plugin Messages id的相关文章

vpp中plugin的api编程

API简介 vpp其实也有自己的control-plane.它们之间的就是使用API来交互,底层是用的共享内存机制.control-plane可以是使用不同的语言来写,支持C/python/java/go 在这里了解的是用C语言与vpp通信.如图1所示.VAT通过命令行来控制VPP. 图1,VAT(vpp api test)与vpp通信: +---------------------+ | | | VPP API TEST + | | +----------+---------+ | binar

【Socket编程】Java中网络相关API的应用

Java中网络相关API的应用 一.InetAddress类 InetAddress类用于标识网络上的硬件资源,表示互联网协议(IP)地址. InetAddress类没有构造方法,所以不能直接new出一个对象: InetAddress类可以通过InetAddress类的静态方法获得InetAddress的对象: 1 InetAddress.getLocalHost();//获取本地对象 2 InetAddress.getByName("");//获取指定名称对象 主要方法使用: 1 /

Maya API编程快速入门

一.Maya API编程简介 Autodesk? Maya? is an open product. This means that anyone outside of Autodesk can change Maya's existing features or add entirely new features. There are several ways you can modify Maya: · MEL?-(Maya Embedded Language) is a powerful

Windows API 编程学习记录&lt;二&gt;

恩,开始写Windows API编程第二节吧. 上次介绍了几个关于Windows API编程最基本的概念,但是如果只是看这些概念,估计还是对Windows API不是很了解.这节我们就使用Windows API 让大家来了解下Windows API的用法. 第一个介绍的Windows API 当然是最经典的MessageBox,这个API 的作用就是在电脑上显示一个对话框,我们先来看看这个API的定义吧: int WINAPI MessageBox(HWND hWnd, LPCTSTR lpTe

Windows API 编程学习记录&lt;三&gt;

恩,开始写API编程的第三节,其实马上要考试了,但是不把这节写完,心里总感觉不舒服啊.写完赶紧去复习啊       在前两节中,我们介绍了Windows API 编程的一些基本概念和一个最基本API函数 MessageBox的使用,在这节中,我们就来正式编写一个Windows的窗口程序. 在具体编写代码之前,我们必须先要了解一下API 编写窗口程序具体的三个基本步骤:             1. 注册窗口类:             2.创建窗口:             3.显示窗口: 恩,

【转】Windows 中不规则窗体的编程实现

一.序言 在绝大多数的Windows应用程序中,其窗体都是使用的正规正矩的矩形窗体,例如我们常用的,“记事本”,“扫雷”,等等.矩形窗体,具有编程实现简单,风格简洁的优点,所以在普通文档应用程序和简单小游戏中使用足矣.但在某些娱乐游戏程序中使用就略显呆板些了,这时若用不规则窗体替代原先的矩形窗体,将会使这类程序更添情趣.典型的例子有windows 自代的Media Player,新版本的Media Player有个控制面板的选项,选中这些面板,播放器就以选中的面板形状出现,这时的播放器比以前版本

Linux统系统开发11 Socket API编程2 多进程 多线程 高并发处理

[本文谢绝转载原文来自http://990487026.blog.51cto.com] <纲要> Linux统系统开发11 Socket API编程2 多进程 多线程 高并发处理 UDP服务器 客户端最小模型,处理字符转大写 TCP 多进程并发服务器模型,为每个客户端开启一个进程: TCP 多线程服务器模型,使用wrap函数封装 作业: ---------------------------------------------------- UDP服务器 客户端最小模型,处理字符转大写 [em

Flink Program Guide (2) -- DataStream API编程指导 -- For Java

v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VML);} .shape {behavior:url(#default#VML);} 张安 张安 2 1 2016-08-02T10:56:00Z 2016-08-02T10:56:00Z 1 2945 16790 139 39 19696 16.00 false false false false

Linux统系统开发12 Socket API编程3 TCP状态转换 多路IO高并发select poll epoll udp组播 线程池

[本文谢绝转载原文来自http://990487026.blog.51cto.com] Linux统系统开发12 Socket API编程3 TCP状态转换 多路IO高并发select  poll  epoll udp组播 线程池 TCP 11种状态理解: 1,客户端正常发起关闭请求 2,客户端与服务端同时发起关闭请求 3,FIN_WAIT1直接转变TIME_WAIT 4,客户端接收来自服务器的关闭连接请求 多路IO转接服务器: select模型 poll模型 epoll模型 udp组播模型 线