ipvlan分析
macvlan
-
每个虚拟接口是一个拥有独立 MAC 的虚拟设备;
-
报文根据目的 MAC 做转发;
-
适用于一些需要独立 MAC 地址的场景,如部分云平台、老旧网络设备下隔离容器网络。
ipvlan
-
所有接口共享一个 MAC 地址(就是物理接口的);
-
报文转发根据 目的 IP 地址 做判定;
-
更适合三层 IP 路由网络,转发更快(少一次二层查找);
-
无需交换机支持多个 MAC 地址。
+--------------------+ Incoming skb -----> | ipvlan_handle_l2() | +--------------------+ | +------------------+------------------+ | | [组播] 是 否 [单播] | | 调用 external_frame() 转发给 l3 逻辑 判断是否应复制广播 ipvlan_handle_l3() | skb_clone() 并 enqueue 到队列
rx_handler_result_t ipvlan_handle_frame(struct sk_buff **pskb) { struct sk_buff *skb = *pskb; struct ipvl_port *port = ipvlan_port_get_rcu(skb->dev); if (!port) return RX_HANDLER_PASS; switch (port->mode) { case IPVLAN_MODE_L2: return ipvlan_handle_mode_l2(pskb, port); case IPVLAN_MODE_L3: return ipvlan_handle_mode_l3(pskb, port); #ifdef CONFIG_IPVLAN_L3S case IPVLAN_MODE_L3S: return RX_HANDLER_PASS; #endif } /* Should not reach here */ WARN_ONCE(true, "ipvlan_handle_frame() called for mode = [%hx]\n", port->mode); kfree_skb(skb); return RX_HANDLER_CONSUMED; } static rx_handler_result_t ipvlan_handle_mode_l2(struct sk_buff **pskb, struct ipvl_port *port) { struct sk_buff *skb = *pskb; struct ethhdr *eth = eth_hdr(skb); rx_handler_result_t ret = RX_HANDLER_PASS; if (is_multicast_ether_addr(eth->h_dest)) { if (ipvlan_external_frame(skb, port)) {//如果是外部流量 struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC); /* External frames are queued for device local * distribution, but a copy is given to master * straight away to avoid sending duplicates later * when work-queue processes this frame. This is * achieved by returning RX_HANDLER_PASS. */ if (nskb) {//是否应当将其发给主接口(如 eth0)之外的其他命名空间(比如其他容器) ipvlan_skb_crossing_ns(nskb, NULL); //通过 ipvlan_multicast_enqueue() 把它入队,供其他容器通过此端口后续异步接收处理 ipvlan_multicast_enqueue(port, nskb, false); } } } else { /* Perform like l3 mode for non-multicast packet */ //L2 模式只特别处理了组播帧,其它行为近似于 L3。 ret = ipvlan_handle_mode_l3(pskb, port); } return ret; } static bool ipvlan_external_frame(struct sk_buff *skb, struct ipvl_port *port) { struct ethhdr *eth = eth_hdr(skb); struct ipvl_addr *addr; void *lyr3h; int addr_type; //判断帧的源 MAC 是否与主设备(如 eth0)的 MAC 相同 if (ether_addr_equal(eth->h_source, skb->dev->dev_addr)) { /*如果相同,说明这个包 是从本地机器发出去的包回环(loopback)回来 是否是我们自己发出的广播包? 如果成功提取 L3 层头(IPv4/IPv6 arp)*/ lyr3h = ipvlan_get_L3_hdr(port, skb, &addr_type); if (!lyr3h) return true; /*查找这个目的地址是否是某个子接口的 IP(但传 false,表示是匹配目的地址而非源地址); 如果命中了,则说明这个包是我们内部某个子接口发出的,且目的也是我们自己,就不需要再多播分发;*/ addr = ipvlan_addr_lookup(port, lyr3h, addr_type, false); if (addr) return false; } return true; } static rx_handler_result_t ipvlan_handle_mode_l3(struct sk_buff **pskb, struct ipvl_port *port) { void *lyr3h; int addr_type; struct ipvl_addr *addr; struct sk_buff *skb = *pskb; rx_handler_result_t ret = RX_HANDLER_PASS; // 当前 ipvlan port,上面挂载多个 ipvlan 虚拟接口 lyr3h = ipvlan_get_L3_hdr(port, skb, &addr_type); if (!lyr3h)//获取arp ipv4 头部 goto out; //在这个 ipvlan port 上查找是否有子接口拥有目标 IP 地址 //(即:看数据包目的地址是不是绑定在某个 ipvlan 虚接口上的); addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true); if (addr) ret = ipvlan_rcv_frame(addr, pskb, false); /*调用 ipvlan_rcv_frame(),相当于把这个包“转送”给该子接口; 内部会修改 skb->dev = addr->device,; 返回 RX_HANDLER_ANOTHER,告诉内核该包由别的设备接管了。 然后重走 netifrcv_rx() 重新投递到网络协议栈上;
同时arp请求 相邻子接口信息,L2 模式下是广播到所有接口,异步调用netif_recv处理
L3 是直接查找对应接口,然后进入改接口的协议栈处理 */ out: return ret; }
发送
static int ipvlan_xmit_mode_l3(struct sk_buff *skb, struct net_device *dev) { const struct ipvl_dev *ipvlan = netdev_priv(dev); void *lyr3h; struct ipvl_addr *addr; int addr_type; lyr3h = ipvlan_get_L3_hdr(ipvlan->port, skb, &addr_type); if (!lyr3h) goto out; //模式有:VEPA + PRIVATE + NONE-没有设置模型,模式为0 if (!ipvlan_is_vepa(ipvlan->port)) { addr = ipvlan_addr_lookup(ipvlan->port, lyr3h, addr_type, true); if (addr) { if (ipvlan_is_private(ipvlan->port)) { //果当前启用了 IPVLAN_F_PRIVATE,说明不允许容器间通信 → 丢弃。 consume_skb(skb); return NET_XMIT_DROP; } return ipvlan_rcv_frame(addr, &skb, true); /*ru果不是 VEPA 模式(即可能是 bridge 模式): 调用 ipvlan_addr_lookup 检查这个目标地址是否是本地其他 ipvlan 子接口的 IP。 如果找到了本地地址 → 表示这是个本地通信流量。*/ } } out: ipvlan_skb_crossing_ns(skb, ipvlan->phy_dev); //如果不是本地地址(或是 VEPA 模式),走默认发送流程 return ipvlan_process_outbound(skb); }
static int ipvlan_process_v4_outbound(struct sk_buff *skb) { const struct iphdr *ip4h = ip_hdr(skb); struct net_device *dev = skb->dev; struct net *net = dev_net(dev); struct rtable *rt; int err, ret = NET_XMIT_DROP; struct flowi4 fl4 = { .flowi4_oif = dev->ifindex, .flowi4_tos = RT_TOS(ip4h->tos), .flowi4_flags = FLOWI_FLAG_ANYSRC, .flowi4_mark = skb->mark, .daddr = ip4h->daddr, .saddr = ip4h->saddr, }; rt = ip_route_output_flow(net, &fl4, NULL); if (IS_ERR(rt)) goto err; if (rt->rt_type != RTN_UNICAST && rt->rt_type != RTN_LOCAL) { ip_rt_put(rt); goto err; } skb_dst_set(skb, &rt->dst); err = ip_local_out(net, skb->sk, skb); if (unlikely(net_xmit_eval(err))) dev->stats.tx_errors++; else ret = NET_XMIT_SUCCESS; goto out; err: dev->stats.tx_errors++; kfree_skb(skb); out: return ret; }
相比L2 模式下发送报文:多了路由,L3有路由,L2直接发送
- 性能优势:L2 模式绕过了内核路由栈,直接转发数据包。
关键行为对比
| 场景 | L2 模式 | L3 模式 |
|---|---|---|
| 本地通信(同一主机) | 直接转发,无开销 | 需走路由栈,性能较低 |
| 跨子网通信 | 依赖外部路由 | 通过主机路由表直接转发 |
| ARP 处理 | 主机代理 ARP 响应 | 需手动配置或依赖外部设备 |
| 广播/多播 | 泛洪到所有 L2 接口 | 按路由表处理(可能被丢弃) |
| 私有模式影响 | 禁止本地通信 | 无影响(依赖路由表) |
性能与配置复杂度
| 指标 | L2 模式 | L3 模式 |
|---|---|---|
| 性能 | 高(直接二层转发) | 中(需路由栈处理) |
| 配置复杂度 | 简单(自动 ARP 代理) | 复杂(需手动管理路由/ARP) |
| 适用场景 | 同一子网的高性能通信(如容器) | 跨子网通信或需要灵活路由的场景 |
IPvlan 的 L2 模式 和 L3 模式 在收发包行为上有显著差异,主要体现在 协议层级处理、通信范围、ARP/路由依赖 以及 性能开销 等方面。以下是详细的对比分析:
1. 接收数据包(RX)
L2 模式
-
处理流程:
- 共享 MAC 地址:所有 IPvlan L2 接口共享主机的 MAC 地址。
- 二层转发:数据包通过物理接口直接接收,无需经过主机协议栈。
- ARP 代理:主机自动响应 ARP 请求(目标为 IPvlan 接口的 IP)。
- 本地通信:若目标地址是同一主机的其他 IPvlan 接口,直接转发(需非私有模式)。
- 广播/多播:泛洪到所有 L2 模式的子接口。
-
特点:
- 本地通信高效:直接通过二层转发,无额外开销。
- 依赖物理网络:跨子网通信需外部路由支持。
L3 模式
-
处理流程:
- 独立 IP 地址:每个 IPvlan 接口有独立的 IP 地址。
- 三层路由:数据包通过主机协议栈处理,依赖路由表。
- ARP 自主处理:需手动配置 ARP 或依赖外部设备响应。
- 本地通信受限:默认不转发本地流量(需显式配置路由)。
- 广播/多播:按路由表处理,可能被丢弃或转发到外部。
-
特点:
- 跨子网支持:天然支持跨子网通信。
- 性能开销:需经过主机路由栈,增加 CPU 和延迟。
2. 发送数据包(TX)
L2 模式
-
处理流程:
- 直接转发:数据包通过物理接口直接发送。
- 目标 MAC 匹配:
- 若目标 MAC 是其他 IPvlan 接口且非私有模式,直接转发。
- 若目标 MAC 是外部设备,依赖物理网络路由。
- 广播/多播:泛洪到物理接口。
-
特点:
- 低延迟:无协议栈处理,直接二层转发。
- 依赖物理交换机:需交换机支持同 MAC 地址的多接口通信。
L3 模式
-
处理流程:
- 路由决策:通过主机路由表确定出口接口(可能是物理接口或外部网关)。
- ARP 请求:若目标 IP 不在同一子网,触发 ARP 请求获取网关 MAC。
- 跨子网通信:通过物理接口发送到网关。
-
特点:
- 灵活性:支持复杂路由策略(如多宿主主机)。
- 性能开销:需经过路由栈和 ARP 处理。
3. 关键行为对比
| 场景 | L2 模式 | L3 模式 |
|---|---|---|
| 本地通信(同一主机) | 直接转发,无开销 | 需走路由栈,性能较低 |
| 跨子网通信 | 依赖外部路由 | 通过主机路由表直接转发 |
| ARP 处理 | 主机代理 ARP 响应 | 需手动配置或依赖外部设备 |
| 广播/多播 | 泛洪到所有 L2 接口 | 按路由表处理(可能被丢弃) |
| 私有模式影响 | 禁止本地通信 | 无影响(依赖路由表) |
4. 性能与配置复杂度
| 指标 | L2 模式 | L3 模式 |
|---|---|---|
| 性能 | 高(直接二层转发) | 中(需路由栈处理) |
| 配置复杂度 | 简单(自动 ARP 代理) | 复杂(需手动管理路由/ARP) |
| 适用场景 | 同一子网的高性能通信(如容器) | 跨子网通信或需要灵活路由的场景 |
5. 典型示例
L2 模式示例
- 场景:同一子网内的两个容器通过 IPvlan L2 模式通信。
- 流程:
- 容器 A 发送数据包到容器 B(目标 MAC 是容器 B 的 IPvlan 接口 MAC)。
- 主机通过 MAC 地址表直接转发到容器 B,无需经过路由栈。
L3 模式示例
- 场景:两个容器位于不同子网,通过 IPvlan L3 模式通信。
- 流程:
- 容器 A 发送数据包到容器 B(目标 IP 在不同子网)。
- 主机路由表将流量转发到网关,网关通过外部网络路由到容器 B。
http代理服务器(3-4-7层代理)-网络事件库公共组件、内核kernel驱动 摄像头驱动 tcpip网络协议栈、netfilter、bridge 好像看过!!!!
但行好事 莫问前程
--身高体重180的胖子

浙公网安备 33010602011771号