VPP添加接口IP地址

2024-04-01 11:12
文章标签 ip 接口 地址 vpp

本文主要是介绍VPP添加接口IP地址,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

如下命令添加接口IPv4地址。

vpp# set interface ip address port6 192.168.1.11/24

配置IP地址由函数ip4_add_del_interface_address_internal处理,主要参数为接口索引,IPv4地址和掩码长度(address_length)。

clib_error_t *
ip4_add_del_interface_address (vlib_main_t * vm,u32 sw_if_index,ip4_address_t * address, u32 address_length, u32 is_del)
{               return ip4_add_del_interface_address_internal(vm, sw_if_index, address, address_length, is_del);
}

接口IPv4地址相关检查

以下函数配置接口sw_if_index的IPv4地址address,前缀长度为address_length。回环接口local0,以及未配置exact-match的VLAN子接口不支持配置IP地址。

static clib_error_t *
ip4_add_del_interface_address_internal (vlib_main_t * vm,u32 sw_if_index, ip4_address_t * address,u32 address_length, u32 is_del)
{vnet_main_t *vnm = vnet_get_main ();ip4_main_t *im = &ip4_main;ip_lookup_main_t *lm = &im->lookup_main;ip4_address_fib_t ip4_af, *addr_fib = 0;error = vnet_sw_interface_supports_addressing (vnm, sw_if_index);if (error) {vnm->api_errno = VNET_API_ERROR_UNSUPPORTED;return error;}

初始化ip4_address_fib_t结构ip4_af,

  ip4_addr_fib_init (&ip4_af, address,vec_elt (im->fib_index_by_sw_if_index, sw_if_index));vec_add1 (addr_fib, ip4_af);

检查地址是否与接口所在FIB中其它接口的地址冲突。首先,遍历接口池pool(vnm->interface_main.sw_interface),找到与配置接口sw_if_index所在FIB相同的接口。

  /* there is no support for adj-fib handling in the presence of overlapping* subnets on interfaces. Easy fix - disallow overlapping subnets, like most routers do.*/if (!is_del) {/* When adding an address check that it does not conflictwith an existing address on any interface in this table. */ip_interface_address_t *ia;vnet_sw_interface_t *sif;pool_foreach (sif, vnm->interface_main.sw_interfaces){if (im->fib_index_by_sw_if_index[sw_if_index] ==im->fib_index_by_sw_if_index[sif->sw_if_index]){

随后,遍历接口上的所有IPv4地址,检查接口上地址是否与将要配置的地址网段冲突,包括三种情况:第一,与已有地址相同网段;第二,包含已有地址;第三,已有地址包含要配置的地址网段。两次调用ip4_destination_matches_route函数实现网段冲突检查,分别用已有地址的掩码长度和配置地址的掩码长度做参数。

如果网段冲突,返回错误。但是,如果发生第一种情况,并且地址冲突的接口与参数中配置接口相同,在前缀不相等的情况下,允许配置,即允许在同一接口上配置同一网段的多个不同IPv4地址。

              foreach_ip_interface_address (&im->lookup_main, ia, sif->sw_if_index, 0 /* honor unnumbered */ ,({ip4_address_t * x = ip_interface_address_get_address(&im->lookup_main, ia);if (ip4_destination_matches_route(im, address, x, ia->address_length) ||ip4_destination_matches_route (im, x, address, address_length)){/* an intf may have >1 addr from the same prefix */if ((sw_if_index == sif->sw_if_index) && (ia->address_length == address_length) &&  (x->as_u32 != address->as_u32))continue;if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE) continue;/* error if the length or intf was different */vnm->api_errno = VNET_API_ERROR_ADDRESS_IN_USE;error = clib_error_create("failed to add %U on %U which conflicts with %U for interface %U",format_ip4_address_and_length, address, address_length, format_vnet_sw_if_index_name, vnm, sw_if_index,format_ip4_address_and_length, x, ia->address_length, format_vnet_sw_if_index_name, vnm, sif->sw_if_index);goto done;}}));}}}

在结构ip_lookup_main_t的哈希成员address_to_if_address_index中查找是否已经存在配置地址对应的地址索引if_address_index,如果此地址索引存在,由地址池中取得接口地址结构ip_interface_address_t。

  if_address_index = ip_interface_address_find (lm, addr_fib, address_length);

如果地址结构ia设置了过期标志,分两种情况处理。第一种,ia中的接口索引值与参数sw_if_index相等,认为是更新操作,去掉过期标志,处理结束。第二种,认为此地址前缀由一个接口移动到另外一个接口,删除旧接口上的地址(还是调用当前函数),在新接口上添加新地址,新地址的索引值填充到了参数if_address_index。

如果找到的地址索引if_address_index有效,并且没有过期标志,表明地址冲突,报错。如果if_address_index无效,直接调用地址添加函数ip_interface_address_add。

  if (!is_del) {                     if (~0 != if_address_index){                     ip_interface_address_t *ia = pool_elt_at_index (lm->if_address_pool, if_address_index);if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE) {if (ia->sw_if_index == sw_if_index) {/* re-adding an address during the replace action. consdier this the update. clear the flag and we're done */ia->flags &= ~IP_INTERFACE_ADDRESS_FLAG_STALE;goto done;} else {/* The prefix is moving from one interface to another. delete the stale and add the new */ip4_add_del_interface_address_internal (vm, ia->sw_if_index, address, address_length, 1);ia = NULL;error = ip_interface_address_add (lm, sw_if_index, addr_fib, address_length, &if_address_index);}} else {vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;error = clib_error_create("Prefix %U already found on interface %U",lm->format_address_and_length, addr_fib, address_length, format_vnet_sw_if_index_name, vnm, ia->sw_if_index);}} elseerror = ip_interface_address_add (lm, sw_if_index, addr_fib, address_length, &if_address_index);}if (error) goto done;

使能接口的Feature。

  ip4_sw_interface_enable_disable (sw_if_index, !is_del);

处理接口IP地址相关路由。在接口UP状态时,调用ip4_add_interface_routes增加接口路由。函数最后调用监听接口地址变化的回调函数。

  ip4_mfib_interface_enable_disable (sw_if_index, !is_del);/* intf addr routes are added/deleted on admin up/down */if (vnet_sw_interface_is_admin_up (vnm, sw_if_index)) {if (!is_del)ip4_add_interface_routes (sw_if_index, im, ip4_af.fib_index, pool_elt_at_index(lm->if_address_pool, if_address_index));}ip4_add_del_interface_address_callback_t *cb;vec_foreach (cb, im->add_del_interface_address_callbacks)cb->function (im, cb->function_opaque, sw_if_index, address, address_length, if_address_index, is_del);

接口地址添加

对于IPv4前缀长度不能大于32,IPv6前缀长度不能大于128,前缀长度也不能为0,非法前缀长度,返回错误。

clib_error_t *
ip_interface_address_add (ip_lookup_main_t * lm, u32 sw_if_index,void *addr_fib, u32 address_length, u32 * result_if_address_index)
{vnet_main_t *vnm = vnet_get_main ();ip_interface_address_t *a, *prev;u32 pi,  /* previous index */   ai,   hi;           /* head index *//* Verify given length. */if ((address_length == 0) || (lm->is_ip6 && address_length > 128) ||(!lm->is_ip6 && address_length > 32)) {vnm->api_errno = VNET_API_ERROR_ADDRESS_LENGTH_MISMATCH;return clib_error_create("%U wrong length for interface %U",lm->format_address_and_length, addr_fib, address_length, format_vnet_sw_if_index_name, vnm, sw_if_index);}

确保向量if_address_pool_index_by_sw_if_index的sw_if_index位置已经分配值,以便保存接口地址的索引。

  vec_validate_init_empty (lm->if_address_pool_index_by_sw_if_index, sw_if_index, ~0);

之后,由if_address_pool地址池中分配ip_interface_address_t结构a,初始化a。

同一接口的所有ip_interface_address_t地址结构组成一个双向链表,第一个ip_interface_address_t结构的索引保存在lm->if_address_pool_index_by_sw_if_index[sw_if_index]中。新添加的地址放在链表的末尾。

最后,返回新分配的地址池索引result_if_address_index;

  pool_get_zero (lm->if_address_pool, a);ai = a - lm->if_address_pool;hi = pi = lm->if_address_pool_index_by_sw_if_index[sw_if_index];prev = 0;while (pi != (u32) ~ 0) {prev = pool_elt_at_index (lm->if_address_pool, pi);pi = prev->next_this_sw_interface;}pi = prev ? prev - lm->if_address_pool : (u32) ~ 0;a->address_key = mhash_set (&lm->address_to_if_address_index, addr_fib, ai, /* old_value */ 0);a->address_length = address_length;a->sw_if_index = sw_if_index;a->flags = 0;a->prev_this_sw_interface = pi;a->next_this_sw_interface = ~0;if (prev) prev->next_this_sw_interface = ai;lm->if_address_pool_index_by_sw_if_index[sw_if_index] = (hi != ~0) ? hi : ai;*result_if_address_index = ai;

接口特性feature

记录接口im->ip_enabled_by_sw_if_index[sw_if_index]对应的数值,仅在首次使能的时候,开启ip4-unicast和ip4-multicast特性。仅在最后一次禁止时,关闭ip4-unicast和ip4-multicast特性。

void ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
{ip4_main_t *im = &ip4_main;vnet_main_t *vnm = vnet_get_main ();vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);/* enable/disable only on the 1<->0 transition */if (is_enable) {if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])return;} else {ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])return;}

如果使能,增加接口l3_if_count计数,否则,递减l3_if_count计数。最后,调用向量enable_disable_interface_callbacks中的注册函数,例如arp_enable_disable_interface,其操作arp-reply特性。

  vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index, !is_enable, 0, 0);vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled", sw_if_index, !is_enable, 0, 0);if (is_enable)hi->l3_if_count++;else if (hi->l3_if_count)hi->l3_if_count--;{ip4_enable_disable_interface_callback_t *cb;vec_foreach (cb, im->enable_disable_interface_callbacks)cb->function (im, cb->function_opaque, sw_if_index, is_enable);}

参见如下接口features的变化。

vpp# show interface features port6
ip4-unicast:none configuredip4-multicast:none configuredvpp# show interface features port6
ip4-unicast:ip4-not-enabledip4-multicast:ip4-not-enabled

接口地址相关多播路由表项

增加Multicast FIB标志的特殊表项。

void ip4_mfib_interface_enable_disable (u32 sw_if_index, int is_enable)
{  const fib_route_path_t path = {.frp_proto = DPO_PROTO_IP4,.frp_addr = zero_addr,.frp_sw_if_index = sw_if_index,.frp_fib_index = ~0,.frp_weight = 1,.frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT,};mfib_index = ip4_mfib_table_get_index_for_sw_if_index(sw_if_index);for (ii = 0; ii < ARRAY_LEN(ip4_specials); ii++) {if (is_enable) {mfib_table_entry_path_update(mfib_index, &ip4_specials[ii],MFIB_SOURCE_SPECIAL, MFIB_ENTRY_FLAG_NONE, &path);}}

如下两个特殊表项:(,224.0.0.1)/32和(,224.0.0.2)/32。

static const mfib_prefix_t ip4_specials[] =
{/* ALL prefixes are in network order */{/* (*,224.0.0.1)/32 - all hosts */.fp_grp_addr = {.ip4.data_u32 = 0x010000e0,},.fp_len = 32,.fp_proto = FIB_PROTOCOL_IP4,},{/* (*,224.0.0.2)/32 - all routers */.fp_grp_addr = {.ip4.data_u32 = 0x020000e0,},.fp_len = 32,.fp_proto = FIB_PROTOCOL_IP4,},
};

接口地址路由

根据IPv4地址,添加接口相关路由。

static void
ip4_add_interface_routes (u32 sw_if_index, ip4_main_t * im, u32 fib_index, ip_interface_address_t * a)
{ip_lookup_main_t *lm = &im->lookup_main;ip4_address_t *address = ip_interface_address_get_address (lm, a);fib_prefix_t pfx = {.fp_len = 32,.fp_proto = FIB_PROTOCOL_IP4,.fp_addr.ip4 = *address,};/* set special routes for the prefix if needed */ip4_add_interface_prefix_routes (im, sw_if_index, fib_index, a);

函数ip4_add_interface_prefix_routes首先添加的前缀路由如下,表项标志connected,attached:

vpp# show fib entry 38
38@9.9.9.0/24 fib:0 index:38 locks:2interface refs:1 entry-flags:connected,attached, src-flags:added,contributing,active, cover:-1path-list:[74] locks:2 uPRF-list:43 len:1 itfs:[2, ]path:[80] pl-index:74 ip4 weight=1 pref=0 attached:  oper-flags:resolved, cfg-flags:glean,port7forwarding:   unicast-ip4-chain[@0]: dpo-load-balance: [proto:ip4 index:40 buckets:1 uRPF:43 to:[0:0]][0] [@4]: ipv4-glean: [src:9.9.9.0/24] port7: mtu:9000 next:1 flags:[] ffffffffffff0060e0689ff00806Delegates:covered:[{entry:41}]Children:

之后是添加一个针对接口地址前缀的路由(9.9.9.0/32),掩码为32位。

vpp# show fib entry 39
39@9.9.9.0/32 fib:0 index:39 locks:2interface refs:1 entry-flags:drop,uRPF-exempt, src-flags:added,contributing,active, cover:-1path-list:[73] locks:2 flags:drop, uPRF-list:41 len:0 itfs:[]path:[79] pl-index:73 ip4 weight=1 pref=0 special:  cfg-flags:drop,[@0]: dpo-drop ip4forwarding:   unicast-ip4-chain[@0]: dpo-load-balance: [proto:ip4 index:41 buckets:1 uRPF:44 to:[0:0]][0] [@0]: dpo-drop ip4Delegates:Children:

之后再添加网段的广播地址路由(9.9.9.255/32)。

vpp# show fib entry 40
40@9.9.9.255/32 fib:0 index:40 locks:2interface refs:1 entry-flags:drop,uRPF-exempt, src-flags:added,contributing,active, cover:-1path-list:[75] locks:2 flags:drop, uPRF-list:45 len:0 itfs:[]path:[81] pl-index:75 ip4 weight=1 pref=0 special:  cfg-flags:drop,[@0]: dpo-drop ip4forwarding:   unicast-ip4-chain[@0]: dpo-load-balance: [proto:ip4 index:42 buckets:1 uRPF:46 to:[0:0]][0] [@0]: dpo-drop ip4Delegates:Children:

如果通过命令,在接口上配置了分类表功能,以下代码增加DPO_CLASSIFY类型的DPO。

  if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index)){u32 classify_table_index = lm->classify_table_index_by_sw_if_index[sw_if_index];if (classify_table_index != (u32) ~ 0) {dpo_id_t dpo = DPO_INVALID;dpo_set (&dpo, DPO_CLASSIFY, DPO_PROTO_IP4, classify_dpo_create (DPO_PROTO_IP4, classify_table_index));fib_table_entry_special_dpo_add (fib_index, &pfx, FIB_SOURCE_CLASSIFY, FIB_ENTRY_FLAG_NONE, &dpo);dpo_reset (&dpo);}}

最后增加接口ipv4地址对应的本地直连路由(FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_LOCAL)。

  fib_table_entry_update_one_path (fib_index, &pfx, FIB_SOURCE_INTERFACE,(FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_LOCAL),DPO_PROTO_IP4, &pfx.fp_addr, sw_if_index,/* invalid FIB index */ ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
}

如下为接口地址9.9.9.1对应的本地直连(connected,local)路由。

vpp# show fib entry 41
41@9.9.9.1/32 fib:0 index:41 locks:2interface refs:1 entry-flags:connected,local, src-flags:added,contributing,active, cover:38path-list:[77] locks:2 flags:local, uPRF-list:48 len:0 itfs:[]path:[83] pl-index:77 ip4 weight=1 pref=0 receive:  oper-flags:resolved, cfg-flags:local,[@0]: dpo-receive: 9.9.9.1 on port7forwarding:   unicast-ip4-chain[@0]: dpo-load-balance: [proto:ip4 index:43 buckets:1 uRPF:48 to:[0:0]][0] [@14]: dpo-receive: 9.9.9.1 on port7Delegates:Children:

这篇关于VPP添加接口IP地址的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/867017

相关文章

详解Java如何向http/https接口发出请求

《详解Java如何向http/https接口发出请求》这篇文章主要为大家详细介绍了Java如何实现向http/https接口发出请求,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 用Java发送web请求所用到的包都在java.net下,在具体使用时可以用如下代码,你可以把它封装成一

Java后端接口中提取请求头中的Cookie和Token的方法

《Java后端接口中提取请求头中的Cookie和Token的方法》在现代Web开发中,HTTP请求头(Header)是客户端与服务器之间传递信息的重要方式之一,本文将详细介绍如何在Java后端(以Sp... 目录引言1. 背景1.1 什么是 HTTP 请求头?1.2 为什么需要提取请求头?2. 使用 Spr

shell脚本快速检查192.168.1网段ip是否在用的方法

《shell脚本快速检查192.168.1网段ip是否在用的方法》该Shell脚本通过并发ping命令检查192.168.1网段中哪些IP地址正在使用,脚本定义了网络段、超时时间和并行扫描数量,并使用... 目录脚本:检查 192.168.1 网段 IP 是否在用脚本说明使用方法示例输出优化建议总结检查 1

Redis连接失败:客户端IP不在白名单中的问题分析与解决方案

《Redis连接失败:客户端IP不在白名单中的问题分析与解决方案》在现代分布式系统中,Redis作为一种高性能的内存数据库,被广泛应用于缓存、消息队列、会话存储等场景,然而,在实际使用过程中,我们可能... 目录一、问题背景二、错误分析1. 错误信息解读2. 根本原因三、解决方案1. 将客户端IP添加到Re

SpringBoot实现基于URL和IP的访问频率限制

《SpringBoot实现基于URL和IP的访问频率限制》在现代Web应用中,接口被恶意刷新或暴力请求是一种常见的攻击手段,为了保护系统资源,需要对接口的访问频率进行限制,下面我们就来看看如何使用... 目录1. 引言2. 项目依赖3. 配置 Redis4. 创建拦截器5. 注册拦截器6. 创建控制器8.

Linux限制ip访问的解决方案

《Linux限制ip访问的解决方案》为了修复安全扫描中发现的漏洞,我们需要对某些服务设置访问限制,具体来说,就是要确保只有指定的内部IP地址能够访问这些服务,所以本文给大家介绍了Linux限制ip访问... 目录背景:解决方案:使用Firewalld防火墙规则验证方法深度了解防火墙逻辑应用场景与扩展背景:

常用的jdk下载地址

jdk下载地址 安装方式可以看之前的博客: mac安装jdk oracle 版本:https://www.oracle.com/java/technologies/downloads/ Eclipse Temurin版本:https://adoptium.net/zh-CN/temurin/releases/ 阿里版本: github:https://github.com/

webapp地址

F:\LSP\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps

Java 后端接口入参 - 联合前端VUE 使用AES完成入参出参加密解密

加密效果: 解密后的数据就是正常数据: 后端:使用的是spring-cloud框架,在gateway模块进行操作 <dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>30.0-jre</version></dependency> 编写一个AES加密

Jenkins 插件 地址证书报错问题解决思路

问题提示摘要: SunCertPathBuilderException: unable to find valid certification path to requested target...... 网上很多的解决方式是更新站点的地址,我这里修改了一个日本的地址(清华镜像也好),其实发现是解决不了上述的报错问题的,其实,最终拉去插件的时候,会提示证书的问题,几经周折找到了其中一遍博文