openVswitch源代码分析之数据结构

OVS2.9.0

Posted by chochi on May 15, 2018

0 实验环境

  1. Ubuntu18.04,Mininet2.3.0,OpenVSwitch2.9.0
  2. 参考链接ovs2.5.4版本,图片和逻辑关系参照这位大佬

  3. ps:把Ubuntu升级了,这篇文章之后都是Ubuntu18,04的环境。

  4. git 最新版本的ovs
# git clone https://github.com/openvswitch/ovs.git --depth=1

1 有关 vport 的数据结构

  • 若无特殊说明,地址: ovs/datapath/vport.h
  • 以下摘录与 vport 有关的代码

1.1 struct vport

//端口结构体 vport
struct vport {
	struct net_device *dev; //指向net_device的指针
	
	struct datapath	*dp; //网桥结构体指针,表示该端口是属于哪个网桥的
	
	struct vport_portids __rcu *upcall_portids; //Netlink端口收到的数据包时使用的端口id  
	
	u16 port_no; //端口号,在网桥的端口数组中的下标
	

	struct hlist_node hash_node; //hash_talbe的实现在 datapash.c  
	
	struct hlist_node dp_hash_node; // 这是网桥的哈希链表元素
	
	const struct vport_ops *ops; // 虚拟端口类,里面有一些函数操作
	

	struct list_head detach_list; //list used for detaching vport in net-exit call.
	struct rcu_head rcu; //RCU callback head for deferred destruction.
};

1.2 struct vport_parms

  • 创建新 vport 时候所需的参数
    struct vport_parms {
      const char *name;//端口名
    	
      enum ovs_vport_type type;//端口类型,枚举类型,在datapath.h
    	
      struct nlattr *options;
    	
      /* For ovs_vport_alloc(). */
    	
      struct datapath *dp;//指向端口所属的网桥
    	
      u16 port_no;//在网中的端口号
    	
      struct nlattr *upcall_portids;
    };
    

1.3 enum ovs_vport_type

  • 端口的枚举类型,地址 datapath.h
enum ovs_vport_type {
	OVS_VPORT_TYPE_UNSPEC,
	OVS_VPORT_TYPE_NETDEV,   /* network device */
	OVS_VPORT_TYPE_INTERNAL, /* network device implemented by datapath */
	OVS_VPORT_TYPE_GRE,      /* GRE tunnel. */
	OVS_VPORT_TYPE_VXLAN,	 /* VXLAN tunnel. */
	OVS_VPORT_TYPE_GENEVE,	 /* Geneve tunnel. */
	OVS_VPORT_TYPE_LISP = 105,  /* LISP tunnel */
	OVS_VPORT_TYPE_STT = 106, /* STT tunnel */
	__OVS_VPORT_TYPE_MAX
};

1.4 struct vport_ops

  • 虚拟端口的定义
struct vport_ops {
	enum ovs_vport_type type;//端口类型
	
	// vport端口模块的初始化加载和卸载函数
	
	struct vport *(*create)(const struct vport_parms *);
	
	/**
	    根据指定的参数创建新的vport,
	    
	    若成功,将从 ovs_vport_alloc()函数返回一个新的端口
	    
	    若失败,将从 ERR_PTR()函数返回错误值
	    
	**/
	
	void (*destroy)(struct vport *);
	
   	 /**
        使用 vport_free()函数销毁端口,
	
        but not before an RCU grace period has elapsed.
	
  	  **/
    
    	 // 得到和设置option成员函数
     
	int (*set_options)(struct vport *, struct nlattr *);
	
	/**
	    修改端口信息,如无法支持,则设置为NULL
	    
	**/
	
	int (*get_options)(const struct vport *, struct sk_buff *);
	
	netdev_tx_t (*send)(struct sk_buff *skb);//使用该设备发送数据包
	
#ifndef USE_UPSTREAM_TUNNEL

	int  (*fill_metadata_dst)(struct net_device *dev, struct sk_buff *skb);
#endif

	struct module *owner;
	struct list_head list;
};

1.5 端口创建函数,端口销毁函数声明

  • 地址: vport.c
struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *,
			      const struct vport_parms *);

void ovs_vport_free(struct vport *);


2 datapath 数据结构

  • 地址: datapash.h
  • datapath for flow-based packet switching
struct datapath {
	struct rcu_head rcu;
	struct list_head list_node;// global 'dps' list, 网桥数组

	/* Flow table. */
	struct flow_table table;// 这是哈希流表,里面包含了哈希桶的地址指针。该哈希表受_rcu机制保护  

	/* Switch ports. */
	struct hlist_head *ports;// 一个网桥有多个端口,这些端口都是用哈希链表来链接的

	/* Stats. */
	struct dp_stats_percpu __percpu *stats_percpu;//Per-CPU datapath statistics.

	/* Network namespace ref. */
	possible_net_t net;//所属的网络

	u32 user_features;

	u32 max_headroom;

	/* Switch meters. */
	struct hlist_head *meters;
};

3 逻辑关系

image

4 流模块

flow.h flow.c

  • 这是key值,主要是提取数据包中协议相关信息,这是后期要进行流表匹配的关键结构
  • ovs -> Documentation -> topics -> datapath.rst 有详细的对 flow key的说明
  • 主要有以下三点:
    • 若 userspace 的flow key 与内核模块所解析的flow key一致,那么按正常流程,没有奇怪的函数被唤醒。
    • 若内核模块解析出来的 flow key 更加细致,如 内核解析出的flow key 为 ipv6,而 userspace 解析出来的为 Ethernet,则userspace使用内核解析的flow key 按照正常流程建立一个 flow。
    • 若 userspace 解析的更为细致,则无需在内核模块建立flow,userspace直接做出数据转发的动作。该动作将导致性能底下。
struct sw_flow_key {
	u8 tun_opts[255];
	u8 tun_opts_len;
	struct ip_tunnel_key tun_key;  /* Encapsulating tunnel key. */
	struct {
		u32	priority;	/* Packet QoS priority. */
		u32	skb_mark;	/* SKB mark. */
		u16	in_port;	/* Input switch port (or DP_MAX_PORTS). */
	} __packed phy; /* Safe when right after 'tun_key'. */
	u8 mac_proto;			/* MAC layer protocol (e.g. Ethernet). */
	u8 tun_proto;                   /* Protocol of encapsulating tunnel. */
	u32 ovs_flow_hash;		/* Datapath computed hash value.  */
	u32 recirc_id;			/* Recirculation ID.  */
	struct {
		u8     src[ETH_ALEN];	/* Ethernet source address. */
		u8     dst[ETH_ALEN];	/* Ethernet destination address. */
		struct vlan_head vlan;
		struct vlan_head cvlan;
		__be16 type;		/* Ethernet frame type. */
	} eth;
	/* Filling a hole of two bytes. */
	u8 ct_state;
	u8 ct_orig_proto;		/* CT original direction tuple IP
					 * protocol.
					 */
	union {
		struct {
			__be32 top_lse;	/* top label stack entry */
		} mpls;
		struct {
			u8     proto;	/* IP protocol or lower 8 bits of ARP opcode. */
			u8     tos;	    /* IP ToS. */
			u8     ttl;	    /* IP TTL/hop limit. */
			u8     frag;	/* One of OVS_FRAG_TYPE_*. */
		} ip;
	};
	u16 ct_zone;			/* Conntrack zone. */
	struct {
		__be16 src;		/* TCP/UDP/SCTP source port. */
		__be16 dst;		/* TCP/UDP/SCTP destination port. */
		__be16 flags;		/* TCP flags. */
	} tp;
	union {
		struct {
			struct {
				__be32 src;	/* IP source address. */
				__be32 dst;	/* IP destination address. */
			} addr;
			union {
				struct {
					__be32 src;
					__be32 dst;
				} ct_orig;	/* Conntrack original direction fields. */
				struct {
					u8 sha[ETH_ALEN];	/* ARP source hardware address. */
					u8 tha[ETH_ALEN];	/* ARP target hardware address. */
				} arp;
			};
		} ipv4;
		struct {
			struct {
				struct in6_addr src;	/* IPv6 source address. */
				struct in6_addr dst;	/* IPv6 destination address. */
			} addr;
			__be32 label;			/* IPv6 flow label. */
			union {
				struct {
					struct in6_addr src;
					struct in6_addr dst;
				} ct_orig;	/* Conntrack original direction fields. */
				struct {
					struct in6_addr target;	/* ND target address. */
					u8 sll[ETH_ALEN];	/* ND source link layer address. */
					u8 tll[ETH_ALEN];	/* ND target link layer address. */
				} nd;
			};
		} ipv6;
		struct ovs_key_nsh nsh;         /* network service header */
	};
	struct {
		/* Connection tracking fields not packed above. */
		struct {
			__be16 src;	/* CT orig tuple tp src port. */
			__be16 dst;	/* CT orig tuple tp dst port. */
		} orig_tp;
		u32 mark;
		struct ovs_key_ct_labels labels;
	} ct;

} __aligned(BITS_PER_LONG/8); /* Ensure that we can do comparisons as longs. */