searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Cilium SRv6相关源码分析

2023-09-25 09:22:53
108
0

1. cilium-高性能CNI

         cilium 高性能的原因:其采用技术创新短路传统了 Kernel 框架,减少了数据包转发所需的指令。这些技术包括,eBPF 加持下的 redirect、redirect_peer、redirect_neigh、XDP、sockmap、sk redirect 等技术。 

         另外实现的Kubernetes service 数据面性能高,Service 规模扩大,控制面下发时间变化不大。 Kubernetes service 数据面性能高,分为集群内访问的 socket LB 技术,该技术使得不需要做数据包 skb 更改,直接将容器平台内部访问 service 流量转变成直接访问 Pod 效果,访问 Pod 路径也是经过加速的。南北向 Service(NodePort、external IP、HostPort)性能高的原因是其支持 Native XDP 加速,外加上路径跳转优化,对于 Remote Pod 的 Service 场景,还支持了 DR 模式,从逻辑上减少一跳路径。 Kubernetes service 控制面下发性能,这块主要采用了 eBPF map 技术,该技术实质会采用 Hash 方法,摆脱了变动 Service 就要全量下发 iptables 的问题,因此控制面下发时间随着 Service 规模的变大,策略更新延时变化不大。 

2. cilium-srv6实现

1. 主要的MAP数据结构:其中用到的bpf数据结构类型包括 BPF_MAP_TYPE_LPM_TRIE,BPF_MAP_TYPE_LRU_HASH,BPF_MAP_TYPE_HASH。其中,SRV6_VRF_MAP4负责通过内网ip和目的cidr查找对应的vrf,SRV6_POLICY_MAP 根据vrf和dst cidr找到对应的目的sid,SRV6_SID_MAP 记录目的sid对应的vrf。SRV6_STATE_MAP记录的是内外网的ip映射。

#ifdef ENABLE_SRV6
# define SRV6_VRF_MAP(IP_FAMILY)				\
struct {						\
	__uint(type, BPF_MAP_TYPE_LPM_TRIE);		\
	__type(key, struct srv6_vrf_key ## IP_FAMILY);	\
	__type(value, __u32);				\
	__uint(pinning, LIBBPF_PIN_BY_NAME);		\
	__uint(max_entries, SRV6_VRF_MAP_SIZE);		\
	__uint(map_flags, BPF_F_NO_PREALLOC);		\
} SRV6_VRF_MAP ## IP_FAMILY __section_maps_btf;

struct srv6_vrf_key4 {
	struct bpf_lpm_trie_key lpm;
	__u32 src_ip;
	__u32 dst_cidr;
};
// 对应的vrf值u32

# define SRV6_POLICY_MAP(IP_FAMILY)				\
struct {							\
	__uint(type, BPF_MAP_TYPE_LPM_TRIE);			\
	__type(key, struct srv6_policy_key ## IP_FAMILY);	\
	__type(value, union v6addr);				\
	__uint(pinning, LIBBPF_PIN_BY_NAME);			\
	__uint(max_entries, SRV6_POLICY_MAP_SIZE);		\
	__uint(map_flags, BPF_F_NO_PREALLOC);			\
} SRV6_POLICY_MAP ## IP_FAMILY __section_maps_btf;


# define SRV6_STATE_MAP(IP_FAMILY)							\
struct {										\
	__uint(type, BPF_MAP_TYPE_LRU_HASH);						\
	__type(key, struct srv6_ipv ## IP_FAMILY ## _2tuple); /* inner header */	\
	__type(value, struct srv6_ipv6_2tuple);               /* outer header */	\
	__uint(pinning, LIBBPF_PIN_BY_NAME);						\
	__uint(max_entries, SRV6_STATE_MAP_SIZE);					\
} SRV6_STATE_MAP ## IP_FAMILY __section_maps_btf;

# ifdef ENABLE_IPV4
SRV6_VRF_MAP(4)
SRV6_POLICY_MAP(4)
SRV6_STATE_MAP(4)

struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __type(key, union v6addr); /* SID */
    __type(value, __u32);      /* VRF ID */
    __uint(pinning, LIBBPF_PIN_BY_NAME);
    __uint(max_entries, SRV6_SID_MAP_SIZE);
    __uint(map_flags, BPF_F_NO_PREALLOC);
} SRV6_SID_MAP __section_maps_btf;

/* Key of an a BPF_MAP_TYPE_LPM_TRIE entry */
struct bpf_lpm_trie_key {
	__u32	prefixlen;	/* up to 32 for AF_INET, 128 for AF_INET6 */
	__u8	data[0];	/* Arbitrary size */
};

struct srv6_vrf_key4 {
	struct bpf_lpm_trie_key lpm;
	__u32 src_ip;
	__u32 dst_cidr;
};

struct srv6_policy_key4 {
	struct bpf_lpm_trie_key lpm;
	__u32 vrf_id;
	__u32 dst_cidr;
};

struct srv6_policy_key6 {
	struct bpf_lpm_trie_key lpm;
	__u32 vrf_id;
	union v6addr dst_cidr;
};

// inner 
struct srv6_ipv4_2tuple {
	__u32 src;
	__u32 dst;
};

struct srv6_ipv6_2tuple {
	union v6addr src;
	union v6addr dst;
};
2. srv6 encap过程
      该函数入口是挂载TC或者XDP上,控制从物理网卡接收到主机测得数据包,里面包括有L7 LB处理,主机防火墙过滤, wigreguard处理,edt带宽控制以及传统的IPV4 IPV6处理等。它们都是通过宏定义开关是否开启 。
     handle_srv6(struct __ctx_buff *ctx)首先检验数据包l2层合法性检查后,根据数据包的类型分ipv4和ipv6分别处理,在ipv4实现中,查找SRV6_STATE_MAP4,如果存在历史已有的记录着数据包src 和目的ipv4对应的srv6的src ipv6和目的ipv6地址,那么直接封装成对应的srv6报文,尾调用CILIUM_CALL_SRV6_REPLY,srv6_handling4稍后介绍。
否则,如果SRV6_STATE_MAP4中不存在,则需要首先根据原始数据包,查找SRV6_VRF_MAP(4) SRV6_POLICY_MAP(4) 通过前缀匹配法则查找对应的vrf和目的sid,并存储在在ctx中,尾调用CILIUM_CALL_SRV6_ENCAP。
尾部调用CILIUM_CALL_SRV6_ENCAP接口实现了两个功能,一个是srv6_handling处理,并根据新的ctx数据包,重新路由ipv6。
 
    Srv6_handing 主要功能查找SRV6_POLICY_MAP(4) 确定src sid,并根据ctx存储的dst sid后,调用srv6_handing4, 那么这个和上面快速直接SRV6_STATE_MAP4 确定src dst sid,最终都是调用同一个函数封装报文 。
 
 
srv6 encapsulation中开始srv6封包,完成外层ipv6报文和srh头的封装
刚好和SRV6报文一一对应
那么上述处理流程:cli_to_netdev ->handle_srv6 ->ENABLE_IPV4-> map_lookup_elem(&SRV6_STATE_MAP4,(struct srv6_ipv4_2tuple *)&ip4->saddr); -> 
tail_srv6_encap ->srv6_handling->srv6_handling4 -> srv6_encapsulation
 
2. srv6 decap过程
 
host测在处理ipv6报文过程中,判定报文是否为srv6报文,然后尾调用。
创建缓存相关,然后
上面是decap的主要过程。
0条评论
0 / 1000
翟云箭
5文章数
0粉丝数
翟云箭
5 文章 | 0 粉丝
原创

Cilium SRv6相关源码分析

2023-09-25 09:22:53
108
0

1. cilium-高性能CNI

         cilium 高性能的原因:其采用技术创新短路传统了 Kernel 框架,减少了数据包转发所需的指令。这些技术包括,eBPF 加持下的 redirect、redirect_peer、redirect_neigh、XDP、sockmap、sk redirect 等技术。 

         另外实现的Kubernetes service 数据面性能高,Service 规模扩大,控制面下发时间变化不大。 Kubernetes service 数据面性能高,分为集群内访问的 socket LB 技术,该技术使得不需要做数据包 skb 更改,直接将容器平台内部访问 service 流量转变成直接访问 Pod 效果,访问 Pod 路径也是经过加速的。南北向 Service(NodePort、external IP、HostPort)性能高的原因是其支持 Native XDP 加速,外加上路径跳转优化,对于 Remote Pod 的 Service 场景,还支持了 DR 模式,从逻辑上减少一跳路径。 Kubernetes service 控制面下发性能,这块主要采用了 eBPF map 技术,该技术实质会采用 Hash 方法,摆脱了变动 Service 就要全量下发 iptables 的问题,因此控制面下发时间随着 Service 规模的变大,策略更新延时变化不大。 

2. cilium-srv6实现

1. 主要的MAP数据结构:其中用到的bpf数据结构类型包括 BPF_MAP_TYPE_LPM_TRIE,BPF_MAP_TYPE_LRU_HASH,BPF_MAP_TYPE_HASH。其中,SRV6_VRF_MAP4负责通过内网ip和目的cidr查找对应的vrf,SRV6_POLICY_MAP 根据vrf和dst cidr找到对应的目的sid,SRV6_SID_MAP 记录目的sid对应的vrf。SRV6_STATE_MAP记录的是内外网的ip映射。

#ifdef ENABLE_SRV6
# define SRV6_VRF_MAP(IP_FAMILY)				\
struct {						\
	__uint(type, BPF_MAP_TYPE_LPM_TRIE);		\
	__type(key, struct srv6_vrf_key ## IP_FAMILY);	\
	__type(value, __u32);				\
	__uint(pinning, LIBBPF_PIN_BY_NAME);		\
	__uint(max_entries, SRV6_VRF_MAP_SIZE);		\
	__uint(map_flags, BPF_F_NO_PREALLOC);		\
} SRV6_VRF_MAP ## IP_FAMILY __section_maps_btf;

struct srv6_vrf_key4 {
	struct bpf_lpm_trie_key lpm;
	__u32 src_ip;
	__u32 dst_cidr;
};
// 对应的vrf值u32

# define SRV6_POLICY_MAP(IP_FAMILY)				\
struct {							\
	__uint(type, BPF_MAP_TYPE_LPM_TRIE);			\
	__type(key, struct srv6_policy_key ## IP_FAMILY);	\
	__type(value, union v6addr);				\
	__uint(pinning, LIBBPF_PIN_BY_NAME);			\
	__uint(max_entries, SRV6_POLICY_MAP_SIZE);		\
	__uint(map_flags, BPF_F_NO_PREALLOC);			\
} SRV6_POLICY_MAP ## IP_FAMILY __section_maps_btf;


# define SRV6_STATE_MAP(IP_FAMILY)							\
struct {										\
	__uint(type, BPF_MAP_TYPE_LRU_HASH);						\
	__type(key, struct srv6_ipv ## IP_FAMILY ## _2tuple); /* inner header */	\
	__type(value, struct srv6_ipv6_2tuple);               /* outer header */	\
	__uint(pinning, LIBBPF_PIN_BY_NAME);						\
	__uint(max_entries, SRV6_STATE_MAP_SIZE);					\
} SRV6_STATE_MAP ## IP_FAMILY __section_maps_btf;

# ifdef ENABLE_IPV4
SRV6_VRF_MAP(4)
SRV6_POLICY_MAP(4)
SRV6_STATE_MAP(4)

struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __type(key, union v6addr); /* SID */
    __type(value, __u32);      /* VRF ID */
    __uint(pinning, LIBBPF_PIN_BY_NAME);
    __uint(max_entries, SRV6_SID_MAP_SIZE);
    __uint(map_flags, BPF_F_NO_PREALLOC);
} SRV6_SID_MAP __section_maps_btf;

/* Key of an a BPF_MAP_TYPE_LPM_TRIE entry */
struct bpf_lpm_trie_key {
	__u32	prefixlen;	/* up to 32 for AF_INET, 128 for AF_INET6 */
	__u8	data[0];	/* Arbitrary size */
};

struct srv6_vrf_key4 {
	struct bpf_lpm_trie_key lpm;
	__u32 src_ip;
	__u32 dst_cidr;
};

struct srv6_policy_key4 {
	struct bpf_lpm_trie_key lpm;
	__u32 vrf_id;
	__u32 dst_cidr;
};

struct srv6_policy_key6 {
	struct bpf_lpm_trie_key lpm;
	__u32 vrf_id;
	union v6addr dst_cidr;
};

// inner 
struct srv6_ipv4_2tuple {
	__u32 src;
	__u32 dst;
};

struct srv6_ipv6_2tuple {
	union v6addr src;
	union v6addr dst;
};
2. srv6 encap过程
      该函数入口是挂载TC或者XDP上,控制从物理网卡接收到主机测得数据包,里面包括有L7 LB处理,主机防火墙过滤, wigreguard处理,edt带宽控制以及传统的IPV4 IPV6处理等。它们都是通过宏定义开关是否开启 。
     handle_srv6(struct __ctx_buff *ctx)首先检验数据包l2层合法性检查后,根据数据包的类型分ipv4和ipv6分别处理,在ipv4实现中,查找SRV6_STATE_MAP4,如果存在历史已有的记录着数据包src 和目的ipv4对应的srv6的src ipv6和目的ipv6地址,那么直接封装成对应的srv6报文,尾调用CILIUM_CALL_SRV6_REPLY,srv6_handling4稍后介绍。
否则,如果SRV6_STATE_MAP4中不存在,则需要首先根据原始数据包,查找SRV6_VRF_MAP(4) SRV6_POLICY_MAP(4) 通过前缀匹配法则查找对应的vrf和目的sid,并存储在在ctx中,尾调用CILIUM_CALL_SRV6_ENCAP。
尾部调用CILIUM_CALL_SRV6_ENCAP接口实现了两个功能,一个是srv6_handling处理,并根据新的ctx数据包,重新路由ipv6。
 
    Srv6_handing 主要功能查找SRV6_POLICY_MAP(4) 确定src sid,并根据ctx存储的dst sid后,调用srv6_handing4, 那么这个和上面快速直接SRV6_STATE_MAP4 确定src dst sid,最终都是调用同一个函数封装报文 。
 
 
srv6 encapsulation中开始srv6封包,完成外层ipv6报文和srh头的封装
刚好和SRV6报文一一对应
那么上述处理流程:cli_to_netdev ->handle_srv6 ->ENABLE_IPV4-> map_lookup_elem(&SRV6_STATE_MAP4,(struct srv6_ipv4_2tuple *)&ip4->saddr); -> 
tail_srv6_encap ->srv6_handling->srv6_handling4 -> srv6_encapsulation
 
2. srv6 decap过程
 
host测在处理ipv6报文过程中,判定报文是否为srv6报文,然后尾调用。
创建缓存相关,然后
上面是decap的主要过程。
文章来自个人专栏
云网络和SDN
5 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
3
0