Linux网络协议栈8--vxlan

本文记录一下vxlan接口内核收发包处理。
VXLAN(Virtual Extensible LAN, 虚拟局域网扩展)是一种网络虚拟化技术,一种大二层隧道技术,将二层包封装在UDP中来构建虚拟的二层网络。
设备厂商特别是大厂vxlan的配置和应用场景要丰富和复杂的多,linux上相对简单,在一些SDN网络,如云计算和容器的一些虚拟化网络中经常用到,还有vxlan上相关的一些支持的特性,如arp proxy、l2miss、l3miss、router等还是比较有意思的。

#####先介绍一下几个重要的数据结构:

struct vxlan_net结构每network namespace(net)一个,保存本namespace中vxlan相关信息。用于vxlan的全局查找,存放在net->gen中。

struct vxlan_net {
	struct list_head  vxlan_list;    // vxlan设备信息,创建vxlan dev(vxlan_newlink)时挂载的vxlan_dev
	struct hlist_head sock_list[PORT_HASH_SIZE];  // vxlan socket信息,vxlan_open创建socket时挂载的vxlan_sock
	spinlock_t	  sock_lock;
};

struct vxlan_dev,是vxlan设备的私有数据结构,保存所有的vxlan配置信息,vxlan的fdb表项,vxlan使用的udp sock信息。

/* Pseudo network device */
struct vxlan_dev {
	struct vxlan_dev_node hlist4;	/* vni hash table for IPv4 socket */
#if IS_ENABLED(CONFIG_IPV6)
	struct vxlan_dev_node hlist6;	/* vni hash table for IPv6 socket */
#endif
	struct list_head  next;		/* vxlan's per namespace list */
	struct vxlan_sock __rcu *vn4_sock;	/* listening socket for IPv4 */
#if IS_ENABLED(CONFIG_IPV6)
	struct vxlan_sock __rcu *vn6_sock;	/* listening socket for IPv6 */
#endif
	struct net_device *dev;
	struct net	  *net;		/* netns for packet i/o */
	struct vxlan_rdst default_dst;	/* default destination */
	u32		  flags;	/* VXLAN_F_* in vxlan.h */

	struct timer_list age_timer;
	spinlock_t	  hash_lock;
	unsigned int	  addrcnt;
	struct gro_cells  gro_cells;

	struct vxlan_config	cfg;                   // vxlan所有配置数据

	struct hlist_head fdb_head[FDB_HASH_SIZE];  // vxlan专门的fdb表项
};

linux的fdb表,是linux用的二层转发表,一般的fdb表表达了某个mac地址的报文从哪个接口送出。而linux为vxlan专门设计的fdb表则多了对vxlan以及其udp tunnel封装方式的表达。
如下图所示,man bridge命令可以看到bridge fdb add命令专门针对vxlan接口的配置项,解释的很清楚。
image.png

如下,我们配置了一个vxlan100,指定了默认的dstport 和 vni,然后又在vxlan上配置了两条fdb表,可以看到可以针对mac地址指定vxlan真正的tunnel封装方式(不同对端),只有在不存在fdb表项的时候才会用静态配置做封装,在SDN网络中非常实用。
除了静态配置的fdb表项,同bridge一样,vxlan也会做src mac学习生产fdb表。

#ip link add vxlan100 type vxlan  dstport 8899  vni 100
// mac为 52:54:00:f7:b4:22的主机的endpoint在172.16.20.12上
#bridge fdb add 52:54:00:f7:b4:22 dev vxlan100 dst 172.16.20.12
// mac为 52:54:00:f7:b4:33的主机的endpoint在172.16.20.13上,port和vni分别为9999和200
#bridge fdb add 52:54:00:f7:b4:33 dev vxlan100 dst 172.16.20.13 port 9999 vni 200

如果在bridge中通过 addif 添加vxlan口,配置fdb表的时候,会在bridge 和vxlan中同时生成fdb表,也就是说bridge中的报文查找bridge的fdb表确认了出接口时vxlan口,进入vxlan_xmit发送,再次查找vxlan的fdb表确认隧道封装。见 rtnl_fdb_add 函数。

struct vxlan_fdb {
	struct hlist_node hlist;	/* linked list of entries */
	struct rcu_head	  rcu;
	unsigned long	  updated;	/* jiffies */
	unsigned long	  used;
	struct list_head  remotes;                     // 插入的 vxlan_rdst,表示一个对端(的用户)
	u8		  eth_addr[ETH_ALEN];       // 表项的mac地址
	u16		  state;	/* see ndm_state */
	u8		  flags;	/* see ndm_flags */
};
// 表示一个vxlan对端(的用户)
struct vxlan_rdst {
	union vxlan_addr	 remote_ip;
	__be16			 remote_port;
	__be32			 remote_vni;
	u32			 remote_ifindex;
	struct list_head	 list;
	struct rcu_head		 rcu;
	struct dst_cache	 dst_cache;
};

vxlan接口创建流程,同各类型虚拟接口类似,主要完成对net_device及其私有结构的 vxlan_dev的相关初始化。

static int vxlan_newlink(struct net *src_net, struct net_device *dev,
			 struct nlattr *tb[], struct nlattr *data[])
{
	// vxlan_config中包含了linux中vxlan支持的所有配置,当然ip link add type vxlan的配置也包含
	struct vxlan_config conf;

	memset(&conf, 0, sizeof(conf));

	......
	// 根据配置创建vxlan虚拟接口设备
	return vxlan_dev_configure(src_net, dev, &conf);
}

static int vxlan_dev_configure(struct net *src_net, struct net_device *dev,
			       struct vxlan_config *conf)
{
	struct vxlan_net *vn = net_generic(src_net, vxlan_net_id);
	struct vxlan_dev *vxlan = netdev_priv(dev), *tmp;
	struct vxlan_rdst *dst = &vxlan->default_dst;
	unsigned short needed_headroom = ETH_HLEN;
	int err;
	bool use_ipv6 = false;
	__be16 default_port = vxlan->cfg.dst_port;
	struct net_device *lowerdev = NULL;

	if (conf->flags & VXLAN_F_GPE) {
		/* For now, allow GPE only together with COLLECT_METADATA.
		 * This can be relaxed later; in such case, the other side
		 * of the PtP link will have to be provided.
		 */
		if ((conf->flags & ~VXLAN_F_ALLOWED_GPE) ||
		    !(conf->flags & VXLAN_F_COLLECT_METADATA)) {
			pr_info("unsupported combination of extensions\n");
			return -EINVAL;
		}

		vxlan_raw_setup(dev);
	} else {
		// 挂载 netdev_ops,指定设备发送函数,open函数等设备处理函数
		vxlan_ether_setup(dev);
	}

	// 根据配置,对vxlan的配置和 default_dst做赋值
	vxlan->net = src_net;

	dst->remote_vni = conf->vni;

	memcpy(&dst->remote_ip, &conf->remote_ip, sizeof(conf->remote_ip));

	/* Unless IPv6 is explicitly requested, assume IPv4 */
	if (!dst->remote_ip.sa.sa_family)
		dst->remote_ip.sa.sa_family = AF_INET;

	if (dst->remote_ip.sa.sa_family == AF_INET6 ||
	    vxlan->cfg.saddr.sa.sa_family == AF_INET6) {
		if (!IS_ENABLED(CONFIG_IPV6))
			return -EPFNOSUPPORT;
		use_ipv6 = true;
		vxlan->flags |= VXLAN_F_IPV6;
	}

	if (conf->label && !use_ipv6) {
		pr_info("label only supported in use with IPv6\n");
		return -EINVAL;
	}
	// 本地绑定接口的校验
	if (conf->remote_ifindex) {
		lowerdev = __dev_get_by_index(src_net, conf->remote_ifindex);
		dst->remote_ifindex = conf->remote_ifindex;

		
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值