openvswitch源代码分析

openvswitch源代码分析
openvswitch源代码分析

Openvswitch(OVS)源代码分析系列

转载请注明原文出处,原文地址为:

https://www.360docs.net/doc/ac10915837.html,/yuzhihui_no1/article/details/39161515

openVswitch(OVS

云计算是现在IT行业比较流行的,但真正什么是云计算业界也没有个什么统一的定义(很多公司都是根据自己的利益狭隘的定义云计算),更别说什么标准规范了。所以现在就有很多人说云计算只不过是个幌子,是个嘘头,没点实用的,嘴上说说而已,虽然我也不太清楚什么叫做云计算,云计算的定义究竟是什么,但我根据我公司现在做的云计算产品来说,对于云计算服务还是懂些的。我觉得那并不是什么幌子、嘘头,但如果说这云计算技术还不太成熟,我倒还勉强认可的。若把云计算比作一个人的话,我个人觉得现在它正是二十岁的样子,到三十多岁就算是比较成熟了,所以大概就能想象的到云计算现在的境况了。下面就来简介下实现云计算的一些技术,我对云计算并没有什么研究,也没能达到从全局的角度来分析云计算技术,更别说从一些更高的位置来分析问题,我所能介绍的仅仅是我一个小程序员在工作中所遇到的一些和云计算有关的技术,日积月累,希望终有一天能成为云计算“砖家”。

云计算是个全世界的话题,所以也有全世界的能人异士来为实现这个云计算而奋斗。我现阶段遇到的有关云计算的技术就是openVswitch、openStack技术和Docker技术。那就先从openVswitch开始介绍起,我会用一系列blog来分析openVswitch的相关数据结构和工作流程,以及各个重要模块的分析。所有的介绍都是基于源码的分析,希望对初学着有点用。

openVswitch,根据其名就可以知道这是一个开放的虚拟交换机(open virtual switch);它是实现网络虚拟化SDN的基础,它是在开源的Apache2.0许可下的产品级质量的多层虚拟交换标准。设计这个openVswitch的目的是为了解决物理交换机存在的一些局限性:openVswitch较物理交换机而言有着更低的成本和更高的工作效率;一个虚拟交换机可以有几十个端口来连接虚拟机,而openVswitch本身占用的资源也非常小;可以根据自己的选

择灵活的配置,可以对数据包进行接收分析处理;同时还支持标准的管理接口和协议,如NetFlow,sFlow,SPAN,RSPAN等。

Open vSwtich模块介绍

当前最新代码包主要包括以下模块和特性:

ovs-vswitchd 主要模块,实现switch的daemon,包括一个支持流交换的Linux内核模块;

ovsdb-server 轻量级数据库服务器,提供ovs-vswitchd获取配置信息;

ovs-brcompatd 让ovs-vswitch替换Linux bridge,包括获取bridge ioctls的Linux 内核模块;

ovs-dpctl 用来配置switch内核模块;

一些Scripts and specs 辅助OVS安装在Citrix XenServer上,作为默认switch;

ovs-vsctl 查询和更新ovs-vswitchd的配置;

ovs-appctl 发送命令消息,运行相关daemon;

ovsdbmonitor GUI工具,可以远程获取OVS数据库和OpenFlow的流表。

ovs-openflowd:一个简单的OpenFlow交换机;

ovs-controller:一个简单的OpenFlow控制器;

ovs-ofctl 查询和控制OpenFlow交换机和控制器;

ovs-pki :OpenFlow交换机创建和管理公钥框架;

ovs-tcpundump:tcpdump的补丁,解析OpenFlow的消息;

上面是网上提到的一些openVswitch的主要模块。其实openVswitch中最主要的还是datapath目录下的一些文件。有端口模块vport等,还有关键的逻辑处理模块datapath 等,以及flow等流表模块,最后的还有action动作响应模块,通道模块等等。

下面来介绍下其工作流程:

一般的数据包在linux网络协议栈中的流向为黑色箭头流向:从网卡上接受到数据包后层层往上分析,最后离开内核态,把数据传送到用户态。当然也有些数据包只是在内核网络协议栈中操作,然后再从某个网卡发出去。

但当其中有openVswitch时,数据包的流向就不一样了。首先是创建一个网桥:ovs-vsctl add-br br0;然后是绑定某个网卡:绑定网卡:ovs-vsctl add-port br0 eth0;这里默认为绑定了eth0网卡。数据包的流向是从网卡eth0上然后到openVswitch的端口vport上进入openVswitch中,然后根据key值进行流表的匹配。如果匹配成功,则根据流表中对应的action找到其对应的操作方法,完成相应的动作(这个动作有可能是把一个请求变成应答,也有可能是直接丢弃,也可以自己设计自己的action);如果匹配不成功,则执行默认的动作,有可能是放回内核网络协议栈中去处理(在创建网桥时就会相应的创建一个端口连接内核协议栈的)。

其大概工作流程就是这样了,在工作中一般在这几个地方来修改内核代码以达到自己的目的:第一个是在datapath.c中的ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb)函数内添加相应的代码来达到自己的目的,因为对于每个数据包来说这个函数都是必经之地;第二个就是自己去设计自己的流表了;第三个和第二个是相关联的,就是根据流表来设计自己的action,完成自己想要的功能。

openVswitch(OVS)源代码分析之数据结构

记得Pascal之父、结构化程序设计的先驱Niklaus Wirth最著名的一本书,书名叫作《算法+ 数据结构= 程序》。还有位传奇的软件工程师Frederick P. Brooks曾经说过:“给我看你的数据”。因此可见数据结构对于一个程序来说是多么的重要,如果你不了解程序中的数据结构,你根本就无法去理解整个程序的工作流程。所以在分析openVswitch(OVS)源代码之前先来了解下openVswitch中一些重要的数据结构,这将对你分析后面的源代码起着至关重要的作用。

按照数据包的流向来分析下涉及到一些重要的数据结构。

第一、vport端口模块中涉及到的一些数据结构:

[cpp]view plain copy

1.// 这是表示网桥中各个端口结构体

2.struct vport {

3.struct rcu_head rcu; // 一种锁机制

4.struct datapath *dp; // 网桥结构体指针,表示该端口是属于哪个

网桥的

5.u32 upcall_portid; // Netlink端口收到的数据包时使用的端口

id

6.u16 port_no; // 端口号,唯一标识该端口

7.

8.// 因为一个网桥上有多个端口,而这些端口都是用哈希链表来存储的,

9.// 所以这是链表元素(里面没有数据,只有next和prev前驱后继指针,数据部

分就是vport结构体中的其他成员)

10.struct hlist_node hash_node;

11.struct hlist_node dp_hash_node; // 这是网桥的哈希链表元

12.const struct vport_ops *ops; // 这是端口结构体的操作函数指

针结构体,结构体里面存放了很多操作函数的函数指针

13.

14.struct pcpu_tstats __percpu *percpu_stats;// vport指向每个

cpu的统计数据使用和维护

15.

16.spinlock_t stats_lock; // 自旋锁,防止异步操作,保护下面的两个

成员

17.struct vport_err_stats err_stats; // 错误状态(错误标识)指出

错误vport使用和维护的统计数字

18.struct ovs_vport_stats offset_stats; // 添加到实际统计数据,

部分原因是为了兼容

19.};

20.

21.// 端口参数,当创建一个新的vport端口是要传入的参数

22.struct vport_parms {

23.const char*name; // 新端口的名字

24.enum ovs_vport_type type; // 新端口的类型(端口不仅仅只有一种

类型,后面会分析到)

25.struct nlattr *options; // 这个没怎么用到过,好像是从Netlink

消息中得到的OVS_VPORT_ATTR_OPTIONS属性

26.

27./* For ovs_vport_alloc(). */

28.struct datapath *dp; // 新的端口属于哪个网桥的

29.u16 port_no; // 新端口的端口号

30.u32 upcall_portid; // 和Netlink通信时使用的端口id

31.};

32.

33.// 这是端口vport操作函数的函数指针结构体,是操作函数的集合,里面存放了

所有有关vport操作函数的函数指针

34.struct vport_ops {

35.enum ovs_vport_type type; // 端口的类型

36.u32 flags; // 标识符

37.

38.// vport端口模块的初始化加载和卸载函数

39.int(*init)(void); // 加载模块函数,不成功则over

40.void(*exit)(void); // 卸载端口模块函数

41.

42.// 新vport端口的创建函数和销毁端口的函数

43.struct vport *(*create)(const struct vport_parms *); //

根据指定的参数配置创建个新的vport,成功返回新端口指针

44.void(*destroy)(struct vport *); // 销毁端口函数

45.

46.// 得到和设置option成员函数

47.int(*set_options)(struct vport *, struct nlattr *);

48.int(*get_options)(const struct vport *, struct sk_buff *

);

49.

50.// 得到端口名称和配置以及发送数据包函数

51.const char*(*get_name)(const struct vport *); // 获取指

定端口的名称

52.void(*get_config)(const struct vport *, void*);// 获取

指定端口的配置信息

53.int(*get_ifindex)(const struct vport *);// 获取系统接口和

设备间的指数

54.int(*send)(struct vport *, struct sk_buff *); // 发送数

据包到设备上

55.};

56.

57.// 端口vport的类型,枚举类型存储

58.enum ovs_vport_type{

59.OVS_VPORT_TYPE_UNSPEC,

60.OVS_VPORT_TYPE_NETDEV,

61.OVS_VPORT_TYPE_INTERNAL,

62.OVS_VPORT_TYPE_GRE,

63.OVS_VPORT_TYPE_VXLAN,

64.OVS_VPORT_TYPE_GRE64 = 104,

65.OVS_VPORT_TYPE_LISP = 105,

66._OVS_VPORT_TYPE_MAX

67.};

第二、网桥模块datapath中涉及到的一些数据结构:

[cpp]view plain copy

1.// 网桥结构体

2.struct datapath {

3.struct rcu_head rcu; // RCU调延迟破坏。

4.struct list_head list_node; // 网桥哈希链表元素,里面只有

next和prev前驱后继指针,数据时该结构体其他成员

5.

6./* Flow table. */

7.struct flow_table __rcu *table;// 这是哈希流表,里面包含了哈

希桶的地址指针。该哈希表受_rcu机制保护

8.

9./* Switch ports. */

10.struct hlist_head *ports;// 一个网桥有多个端口,这些端口都是用

哈希链表来链接的

11.

12./* Stats. */

13.struct dp_stats_percpu __percpu *stats_percpu;

14.

15.#ifdef CONFIG_NET_NS

16./* Network namespace ref. */

17.struct net *net;

18.#endif

19.};

其实上面的网桥结构也表示了整个openVswitch(OVS)的结构,如果能捋顺这些结构的关系,那就对分析openVswitch源代码有很多帮助,下面来看下这些结构的关系图:

第三、流表模块flow中涉及到的一些数据结构:

[cpp]view plain copy

1.// 可以说这是openVswitch中最重要的结构体了(个人认为)

2.// 这是key值,主要是提取数据包中协议相关信息,这是后期要进行流表匹配的

关键结构

3.struct sw_flow_key {

4.// 这是隧道相关的变量

5.struct ovs_key_ipv4_tunnel tun_key; /* Encapsulating tunn

el key. */

6.struct{

7.// 包的优先级

8.u32 priority; // 包的优先级

9.u32 skb_mark; // 包的mark值

10.u16 in_port; // 包进入的端口号

11.} phy; // 这是包的物理层信息结构体提取到的

12.struct{

13.u8 src[ETH_ALEN]; // 源mac地址

14.u8 dst[ETH_ALEN]; // 目的mac地址

15.__be16 tci; // 这好像是局域网组号

16.__be16 type; // 包的类型,即:是IP包还是ARP包

17.} eth; // 这是包的二层帧头信息结构体提取到的

18.struct{

19.u8 proto; // 协议类型TCP:6;UDP:17;ARP类

型用低8位表示

20.u8 tos; // 服务类型

21.u8 ttl; // 生存时间,经过多少跳路由

22.u8 frag; // 一种OVS中特有的

OVS_FRAG_TYPE_*.

23.} ip; // 这是包的三层IP头信息结构体提取到的

24.// 下面是共用体,有IPV4和IPV6两个结构,为了后期使用IPV6

适应

25.union{

26.struct{

27.struct{

28.__be32 src; // 源IP地址

29.__be32 dst; // 目标IP地址

30.} addr; // IP中地址信息

31.// 这又是个共用体,有

ARP包和TCP包(包含UDP)两种

32.union{

33.struct{

34.__be16 src; // 源端口,应用层

发送数据的端口

35.__be16 dst; // 目的端口,也是

指应用层传输数据端口

36.} tp; // TCP(包含UDP)地址提取

37.struct{

38.u8 sha[ETH_ALEN]; // ARP头中

源Mac地址

39.u8 tha[ETH_ALEN]; // ARP头中

目的Mac地址

40.} arp;ARP头结构地址提取

41.};

42.} ipv4;

43.// 下面是IPV6的相关信息,基本和IPV4类似,

这里不讲

44.struct{

45.struct{

46.struct in6_addr src; /* IPv6

source address. */

47.struct in6_addr dst; /* IPv6

destination address. */

48.} addr;

49.__be32 label; /* IPv6 fl

ow label. */

50.struct{

51.__be16 src; /* TCP/UDP sourc

e port. */

52.__be16 dst; /* TCP/UDP desti

nation port. */

53.} tp;

54.struct{

55.struct in6_addr target; /* ND targe

t address. */

56.u8 sll[ETH_ALEN]; /* ND source

link layer address. */

57.u8 tll[ETH_ALEN]; /* ND target

link layer address. */

58.} nd;

59.} ipv6;

60.};

61.};

接下来要分析的数据结构是在网桥结构中涉及的的:struct flow_table __rcu *table;

[cpp]view plain copy

1.//流表

2.struct flow_table {

3.struct flex_array *buckets; //哈希桶地址指针

4.unsigned int count, n_buckets; // 哈希桶个数

5.struct rcu_head rcu; // rcu包含机制

6.struct list_head *mask_list; // struct sw_flow_mask链表头

指针

7.int node_ver;

8.u32 hash_seed; //哈希算法需要的种子,后期匹配时要用到

9.bool keep_flows; //是否保留流表项

10.};

顺序分析下去,应该是分析哈希桶结构体了,因为这个结构体设计的实在是太巧妙了。所以应该仔细的分析下。

这是一个共用体,是个设计非常巧妙的共用体。因为共用体的特点是:整个共用体的大小是其中最大成员变量的大小。也就是说共用体成员中某个最大的成员的大小就是共用体的大小。正是利用这一点特性,最后一个char padding[FLEX_ARRAY_BASE_SIZE]其实是没有用的,仅仅是起到一个占位符的作用了。让整个共用体的大小为

FLEX_ARRAY_BASE_SIZE(即是一个页的大小:4096),那为什么要这么费劲心机去设计呢?是因为struct flex_array_part *parts[]; 这个结构,这个结构并不多见,因为在标准的c/c++代码中是无效的,只有在GNU下才是合法的。这个称为弹性数组,或者可变数组,和常规的数组不一样。这里这个弹性数组的大小是一个页大小减去前面几个整型成员变量后所剩的大小。

[cpp]view plain copy

1.// 哈希桶结构

2.struct flex_array {

3.// 共用体,第二个成员为占位符,为共用体大小

4.union{

5.// 对于这个结构体的成员数据含义,真是花了我不少时间来研

究,发现有歧义,(到后期流表匹配时会详细分析)。现在就我认为最正确的理解来分析

6.struct{

7.int element_size; // 无疑这是数组元素的大

8.int total_nr_elements; // 这是数组元素的总个

9.int elems_per_part; // 这是每个part指针指向

的空间能存储多少元素

10.u32 reciprocal_elems;

11.struct flex_array_part *parts[]; // 结构体指

针数组,里面存放的是struct flex_array_part结构的指针

12.};

13./*

14.* This little trick makes sure that

15.* sizeof(flex_array) == PAGE_SIZE

16.*/

17.char padding[FLEX_ARRAY_BASE_SIZE];

18.};

19.};

20.

21.// 其实struct flex_array_part *parts[];中的结构体只是一个数组而

22.struct flex_array_part {

23.char elements[FLEX_ARRAY_PART_SIZE]; // 里面是一个页大小的字

符数组

24.};

25.

26.// 上面的字符数组中存放的就是流表项头指针,流表项也是用双链表链接而成

27.//流表项结构体

28.struct sw_flow {

29.struct rcu_head rcu; // rcu保护机制

30.struct hlist_node hash_node[2]; // 两个节点指针,用来链接作用,

前驱后继指针

31.u32 hash; // hash值

32.

33.struct sw_flow_key key; // 流表中的key值

34.struct sw_flow_key unmasked_key; // 也是流表中的key

35.struct sw_flow_mask *mask; // 要匹配的mask结构体

36.struct sw_flow_actions __rcu *sf_acts; // 相应的action动

37.

38.spinlock_t lock; // 保护机制自旋锁

39.unsigned long used; // 最后使用的时间

40.u64 packet_count; // 匹配过的数据包数量

41.u64 byte_count; // 匹配字节长度

42.u8 tcp_flags; // TCP标识

43.};

顺序下来,应该轮到分析mask结构体链表了:

[cpp]view plain copy

1.// 这个mask比较简单,就几个关键成员

2.struct sw_flow_mask {

3.int ref_count;

4.struct rcu_head rcu;

5.struct list_head list;// mask链表元素,因为mask结构是个双链

表结构体

6.struct sw_flow_key_range range;// 操作范围结构体,因为key值中

有些数据时不要用来匹配的

7.struct sw_flow_key key;// 要和数据包操作的key,将要被用来匹配

的key值

8.};

9.

10.// key的匹配范围,因为key值中有一部分的数据时不用匹配的

11.struct sw_flow_key_range {

12.size_t start; // key值匹配数据开始部分

13.size_t end; // key值匹配数据结束部分

14.};

下面是整个openVswitch中数据结构所构成的图示,也是整个openVswitch中主要结构:

openVswitch(OVS)源代码分析之工作流程(收发数据包)

前面已经把分析openVswitch源代码的基础(openVswitch(OVS)源代码分析之数据结构)写得非常清楚了,虽然访问的人比较少,也因此让我看到了一个现象:第一篇,openVswitch(OVS)源代码分析之简介其实就是介绍了下有关于云计算现状和openVswitch的各个组成模块,还有笼统的介绍了下其工作流程,个人感觉对于学习openVswitch源代码来说没有多大含金量。云计算现状是根据公司发展得到的个人体会,对学习openVswitch源代码其实没什么帮助;openVswitch各个组成模块到网上一搜一大堆,更别说什么含金量了;最后唯一一点还算过的去的就是openVswitch工作流程图,对从宏

观方面来了解整个openVswitch来说还算是有点帮助的。但整体感觉对于学openVswitch

源代码没有多少实质性的帮助,可是访问它的人就比较多。相反,第二篇,openVswitch(OVS)源代码分析之数据结构分析了整个openVswitch源代码中涉及到的主要数据结构,这可是

花了我不少精力。它也是分析整个源代码的重要基础,更或者说可以把它当做分析openVswitch源代码的字典工具。可是访问它的人数却是少的可怜,为什么会这样呢?

网上有很多blog写有关于openVswitch的,但是绝大部分只是介绍openVswitch以及怎么安装配置它,或者是一些命令的解释。对于源代码的分析是非常少的,至少我开始学习openVswitch时在网上搜资料那会是这样的。因此对于一个开始接触学习openVswitch源

代码的初学者来说是非常困难的,什么资料都没有(当然官网上还是有些资料得,如果你英文够好,看官网的资料也是个不错的选择),只得从头开始去分析,可是要想想openVswitch 是由一个世界级的杰出团队花几年的时间设计而成的,如果要从零开始学习分析它,要到猴

年马月。所幸的是我开始学的时候,公司前辈们提供了些学习心得以及结构资料,所以在此

我也把自己的学习心得和一些理解和大家分享。如有不正确之处,望大家指正,谢谢!!!

言归正传,基础已经学习过了,下面来正真分析下openVswitch的工作流程源代码。

首先是数据包的接受函数,这是在加载网卡时把网卡绑定到openVswitch端口上(ovs-vsctl add-port br0 eth0),绑定后每当有数据包过来时,都会调用该函数,把数据包传送给这个函数去处理。而不是像开始那样(未绑定前)把数据包往内核网络协议栈中发送,让内核协议栈去处理。openVswitch中数据包接受函数为:void ovs_vport_receive(struct

vport *vport, struct sk_buff *skb);函数,该函数所在位置为:datapath/vport.c中。实现如下:[cpp]view plain copy

1.// 数据包接受函数,绑定网卡后,所有数据包都是从这个函数作为入口传入到

openVswitch中去处理的,

2.// 可以说这是openVswitch的入口点。参数vport:数据包从哪个端口进来的;

参数skb:数据包的地址指针

3.void ovs_vport_receive(struct vport *vport, struct sk_buff *skb)

4.{

5.struct pcpu_tstats *stats; // 其实这个东西一直没弄明白,大概

作用是维护CPU的锁状态

6.

7.stats = this_cpu_ptr(vport->percpu_stats); // 开始获取到CPU

的锁状态,这和linux内核中的自旋锁类似

8.u64_stats_update_begin(&stats->syncp); // 开始上锁

9.stats->rx_packets++; // 统计数据包的个数

10.stats->rx_bytes += skb->len; // 记录数据包中数据的大小

11.u64_stats_update_end(&stats->syncp);// 结束锁状态

12.

13.if(!(vport->ops->flags & VPORT_F_TUN_ID)) // 这是种状态处

14.OVS_CB(skb)->tun_key = NULL;

15.

16.// 其实呢这个函数中下面这行代码才是关键,如果不是研究openVswitch而是为

了工作,个人觉得没必要(估计也不可能)

17.// 去弄清楚每条代码的作用。只要知道大概是什么意思,关键代码有什么作用,

如果要添加自己的代码时,该往哪个地方添加就可以了。

18.// 下面这行代码是处理数据包的函数调用,是整个openVswitch的核心部分,传

入的参数和接受数据包函数是一样的。

19.ovs_dp_process_received_packet(vport, skb);

20.}

俗话说有接必有还,有进必有出嘛。上面的是数据包进入openVswitch的函数,那一定有其对应的出openVswitch的函数。数据包进入openVswitch后会调用函数

ovs_dp_process_received_packet(vport,skb);对数据包进行处理,到后期会分析到,这个

函数对数据包进行流表的匹配,然后执行相应的action。其中action动作会操作对数据包进行一些修改,然后再把数据包发送出去,这时就会调用vport.c中的数据包发送函

数:ovs_vport_send(struct vport *vport, struct sk_buff *skb);来把数据包发送到端口绑定的网卡设备上去,然后网卡驱动就好把数据包中的数据发送出去。当然也有些action会把数据包直接向上层应用发送。下面来分析下数据包发送函数的实现,函数所在

位置为:datapath/vport.c中。

[cpp]view plain copy

1.// 这是数据包发送函数。参数vport:指定由哪个端口发送出去;参数skb:指定

把哪个数据包发送出去

2.int ovs_vport_send(struct vport *vport, struct sk_buff *skb)

3.{

4.// 这是我自己加的代码,为了过滤掉ARP数据包。这里额外的插一句,不管在什

么源代码中添加自己的代码时

5.// 都要在代码开头处做上自己的标识,因为这样不仅便于自己修改和调试、维护,

而且也让其他人便于理解

6./*===========yuzhihui:==============*/

7.if(0x806 == ntohs(skb->protocol)) {

8.arp_proc_send(vport,skb);// 自定义了一个函数处理了

ARP数据包

9.}

10.// 在前篇数据结构中讲了ops是vport结构中的一些操作函数的函数指

针集合结构体

11.// 所以vport->ops->send()是函数指针来调用函数,把数据

包发送出去

12.int sent = vport->ops->send(vport, skb);

13.

14.if(likely(sent)) { // 定义了一个判断宏likely(),如果发送成

功执行下面

15.struct pcpu_tstats *stats; // 下面的这些代码是不是觉

得非常眼熟,没错就是接受函数中的那些代码

16.

17.stats = this_cpu_ptr(vport->percpu_stats);

18.

19.u64_stats_update_begin(&stats->syncp);

20.stats->tx_packets++;

21.stats->tx_bytes += sent;

22.u64_stats_update_end(&stats->syncp);

23.}

24.return sent; // 返回的sent是已经发送成功的数据长度

25.}

这两个函数就是openVswitch中收发数据包函数了,对这两个函数没有完全去分析它的所有代码,这也不是我的本意,我只是想让初学者知道这是数据包进入和离开openVswitch 的函数。其实知道了这个是非常有用的,因为不管你是什么数据包,只要是到该主机的(当然了包括主机内的各种虚拟机及服务器),全部都会经过这两个函数(对于接受的数据时一定要进过接受函数的,但是发送数据包有时候到不了发送函数的),那么要对数据包进行怎么样的操作那就全看你想要什么操作了。

在这两个函数中对数据包操作举例:

数据包接受函数中操作:如果你要阻断和某个IP主机间的通信(或者对某个IP主机数据包进行特殊处理),那么你可以在数据进入openVswitch的入口函数

(ovs_vport_receive(struct vport *vport, struct sk_buff *skb);)中进行处理,判断数据包中提取到的IP对比,如果是指定IP则把这个数据包直接销毁掉(也可以自己定义函数做些特殊操作)。这样就可以对整个数据进行控制。

数据包发送函数中操作:就像上面的函数中我自己写的那些代码一样,提取数据包中数据包类型进行判断,当判断如果是ARP数据包时,则调用我自定义的

arp_proc_send(vport,skb);函数进行去处理,而不是贸然的直接把它发送出去,因为你不知道该数据包发送的端口是什么类型的。如果是公网IP端口,那么就在自定义函数中直接把这个数据包掐死掉(ARP数据包是在局域网内作用的,就算发到公网上也会被处理掉的);如果是发送到外层局域网中或者是相连的服务器中,则修改数据包中的目的Mac地址进行洪发;又如果是个ARP请求数据包,则把该数据包修改为应答包,再原路发送回去,等等情况;这些操作控制都是在发送数据包函数中做的手脚。

以上就是openVswitch(OVS)工作流程中的数据包收发函数,经过大概的分析和应用举例说明,我想对于初学者来说应该知道大概在哪个地方添加自己的代码,实现自己的功能要求了。

openVswitch(OVS)源代码分析之工作流程(数据包处理)

上篇分析到数据包的收发,这篇开始着手分析数据包的处理问题。在openVswitch中数据包的处理是其核心技术,该技术分为三部分来实现:第一、根据skb数据包提取相关信息封装成key值;第二、根据提取到key值和skb数据包进行流表的匹配;第三、根据匹配到的流表做相应的action操作(若没匹配到则调用函数往用户空间传递数据包);其具体的代码实现在 datapath/datapath.c 中的,函数为:void

ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb);当接受到一个数据包后,自然而然的就应该是开始对其进行处理了。所以其实在上篇的openVswitch (OVS)源代码分析之工作流程(收发数据包)中的接受数据包函数:void

ovs_vport_receive(struct vport *vport, struct sk_buff *skb)中已有体现,该函数在最后调用了ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb);来把数据包传递到该函数中去进行处理。也由此可见所有进入到openVswitch的数据包都必须经过ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb);函数的处理。所以说ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb);是整个openVswitch的中间枢纽,是openVswitch的核心部分。

对于ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb);的重要性已经解释的非常清楚,紧接着就应该分析该函数源代码了,在分析源代码之前还是得提醒下,其中涉及到很多数据结构,如果有些陌生可以到openVswitch(OVS)源代码分析之数据结构中进行查阅,最好能先大概的看下那文章,了解下其中的数据结构,对以后分析源代码有很大的帮助。

下面来分析几个ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb);函数中涉及到但在openVswitch(OVS)源代码分析之数据结构又没有分析到的数据结构:

第一个、是数据包的统计结构体,是CPU用来对所有数据的一个统计作用:

[cpp]view plain copy

1.// CPU对给定的数据包处理统计

2.struct dp_stats_percpu {

3.u64 n_hit; // 匹配成功的数据包个数

4.u64 n_missed; // 匹配失败的数据包个数,n_hit + n_missed就是

接受到的数据包总和

5.u64 n_lost; // 丢失的数据包个数(可能是datapath队列溢出导

致)

6.struct u64_stats_sync sync;

7.};

第二、是数据包发送到用户空间的参数结构体,在匹配流表没有成功时,数据将发送到用户空间。而内核空间和用户空间进行数据交互是通过netLinks来实现的,所以这个函数就是为了实现netLink通信而设置的一些参数:

[cpp]view plain copy

1.// 把数据包传送给用户空间所需的参数结构体

2.struct dp_upcall_info {

3.u8 cmd; // 命令,OVS_PACKET_CMD_ *之一

4.const struct sw_flow_key *key; // key值,不能为空

5.const struct nlattr *userdata; // 数据的大小,若为空,

OVS_PACKET_ATTR_USERDATA传送到用户空间

6.u32 portid; // 发送数据包的Netlink的PID,其实就是netLink通

信的id号

7.};

下面是来分析ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb);函数的实现源代码:

[cpp]view plain copy

1.// 数据包的处理函数,openVswitch的核心部分

2.void ovs_dp_process_received_packet(struct vport *p, struct sk_buff

*skb)

3.{

4.struct datapath *dp = p->dp; // 定义网桥变量,得到端口所在

的网桥指针

5.struct sw_flow *flow; // 流表

6.struct dp_stats_percpu *stats; // cpu中对数据包的统计

7.struct sw_flow_key key; // skb中提取到的key值

8.

9.

10.u64 *stats_counter;

11.int error;

12.// 这应该是linux内核中的,openVswitch中很多是根据linux内核

设计而来的

13.// 这里应该是对网桥中的数据包统计属性进行初始化

14.stats = this_cpu_ptr(dp->stats_percpu);

15.

16.// 根据端口和skb数据包的相关值进行提取,然后封装成key值

17.error = ovs_flow_extract(skb, p->port_no, &key);

18.if(unlikely(error)) { // 定义宏来判断key值得提取封装是否成

19.kfree_skb(skb);// 如果没有成功,则销毁掉skb数据包,然后

直接退出

20.return;

21.}

22.

23.// 调用函数根据key值对流表中所有流表项进行匹配,把结果返回到

flow中

24.flow = ovs_flow_lookup(rcu_dereference(dp->table), &key);

25.if(unlikely(!flow)) { // 定义宏判断是否匹配到相应的流表项,

如没有,执行下面代码

26.struct dp_upcall_info upcall; // 定义一个结构体,设置

相应的值,然后把数据包发送到用户空间

27.// 下面是根据dp_upcall_info数据结构,对其成员进行填

28.upcall.cmd = OVS_PACKET_CMD_MISS;// 命令

29.upcall.key = &key;// key值

https://www.360docs.net/doc/ac10915837.html,erdata = NULL;// 数据长度

31.upcall.portid = p->upcall_portid;// netLink通信时的

id号

32.ovs_dp_upcall(dp, skb, &upcall);// 把数据包发送到用户

空间

33.consume_skb(skb);// 销毁skb

34.stats_counter = &stats->n_missed;// 用未匹配到流表项

的包数,给计数器赋值

35.goto out;// goto语句,内部跳转,跳转到out处

36.}

37.// 在分析下面的代码时,先看下OVS_CB()这个宏:

#define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb)

38.// 这个宏如果知道skb数据结构的话,就好理解。大概的意思是

把skb中保存的当前层协议信息的数据强转为ovs_skb_cb*数据指针

39.OVS_CB(skb)->flow = flow;// 能够执行到这里,说明匹配到了流表。

把匹配到的流表想flow赋值给结构体中成员

40.OVS_CB(skb)->pkt_key = &key;// 同上,把相应的key值赋值到结构

体变量中

41.// 这是匹配成功的,用匹配成功的数据包数赋值于计数器变

42.stats_counter = &stats->n_hit;

43.ovs_flow_used(OVS_CB(skb)->flow, skb);// 调用函数调整流表项成

员变量(也许是用来流表项的更新)

44.ovs_execute_actions(dp, skb); // 根据匹配到的流表项(已经在

skb中的cb)执行相应的action操作

45.

46.out:

47.// 这是流表匹配失败,数据包发到用户空间后,跳转到该处,

48.// 对处理过的数据包数进行调整(虽然没匹配到流表,但也算是处理

掉了一个数据包,所以计数器变量应该增加1)

49.u64_stats_update_begin(&stats->sync);

50.(*stats_counter)++;

51.u64_stats_update_end(&stats->sync);

52.}

上面就是openVswitch的核心部分,所有的数据包都要经过此函数进行逻辑处理。这只是一个逻辑处理的大体框架,还有一些细节(key值得提取,流表的匹配查询,数据传输到用户空间,根据流表执行相应action)将在后面分析。当把整个openVswitch的工作流程梳理清晰,会发现这其实就是openVswitch的头脑部分,所有的逻辑处理都在里实现,所以我们自己添加代码时,这里往往也是个不错的选择。

如果看了前面那篇openVswitch(OVS)源代码分析之工作流程(收发数据包),那么应该记得其中也说到了可以在收发函数中添加自己代码,因为一般来说收发函数也是数据包的必经之地(发送函数可能不是)。那么怎么区分在哪里添加自己代码合适呢?

其实在接受数据包函数中添加自己代码和在这里的逻辑处理函数中添加自己代码,没有多大区别,因为接受函数中没有做什么处理就把数据包直接发送打逻辑处理函数中去了,所以这两个地方添加自己代码其实是没什么区别的。但是从习惯和规范来说,数据包接受函数只是根据条件控制数据包的接受,并不对数据包进行逻辑上的处理,也不会对数据包进行修改等操作。而逻辑处理函数是会对数据包进行某些逻辑上的处理。(最明显的是修改数据包内的数据,一般来说接受数据包函数中是不会对数据包内容修改的,但逻辑处理函数则有可能会去修改的)。

而在数据包发送函数中添加自己代码和逻辑函数中添加自己代码也有些区别,数据包发送函数其性质和接受函数一样,一般不会去修改数据包,而仅仅是根据条件判断该数据包是否发送而已。

那下面就逻辑处理函数中添加代码来举例:

假若要把某个指定的IP主机上发来的ARP数据包进行处理,把所有的请求数据包变成应答数据包,原路返回。这里最好就是把自己的代码添加到逻辑处理函数中去(如果你要强制的添加到数据包接受函数中去也可以),因为这里要修改数据包的内容,是一个逻辑处理。具体实现:可以在key值提取前对数据包进行判断,看是否是ARP数据包,并且是否是指定IP主机发来的。若不是,交给系统去处理;若是,则对Mac地址和IP地址进行交换,并且把请求标识变成应答标识;最后调用发送函数从原来的端口直接发送出去。这只是一个简单的应用,旨在说明逻辑处理代码最好添加到逻辑处理函数中去。如果要处理复杂的操作也是可以的,比如定义自己的流表,然后然后屏蔽掉系统的流表查询,按自己的流表来操作。这就是一个对openVswitch比较大的改造了,流表、action、流表匹配等这些openVswitch 主要功能和结构都要自己去定义实现完成。

以上分析得就是openVswitch的核心部分,当然了只是一个大体框架而已,后续将会逐步完善。

Android源代码结构分析

目录 一、源代码结构 (2) 第一层次目录 (2) bionic目录 (3) bootloader目录 (5) build目录 (7) dalvik目录 (9) development目录 (9) external目录 (13) frameworks目录 (19) Hardware (20) Out (22) Kernel (22) packages目录 (22) prebuilt目录 (27) SDK (28) system目录 (28) Vendor (32)

一、源代码结构 第一层次目录 Google提供的Android包含了原始Android的目标机代码,主机编译工具、仿真环境,代码包经过解压缩后,第一级别的目录和文件如下所示: . |-- Makefile (全局的Makefile) |-- bionic (Bionic含义为仿生,这里面是一些基础的库的源代码) |-- bootloader (引导加载器),我们的是bootable, |-- build (build目录中的内容不是目标所用的代码,而是编译和配置所需要的脚本和工具) |-- dalvik (JAVA虚拟机) |-- development (程序开发所需要的模板和工具) |-- external (目标机器使用的一些库) |-- frameworks (应用程序的框架层) |-- hardware (与硬件相关的库) |-- kernel (Linux2.6的源代码) |-- packages (Android的各种应用程序) |-- prebuilt (Android在各种平台下编译的预置脚本) |-- recovery (与目标的恢复功能相关) `-- system (Android的底层的一些库)

Struts2框架工作原理及应用体会

2012年第11卷第6期 产业与科技论坛2012.(11).6 Industrial &Science Tribune Struts2框架工作原理及应用体会 □宋 君 张家爱 【摘要】通过针对特定用户的分析,搭建以Struts2为技术核心的旅行社管理系统。本文简单的介绍了MVC 、 Struts2的工作原理,同时总结了在项目制作过程中所得到的心得。 【关键词】 Struts2;MVC ;FilterDispatcher ;Action 【基金项目】本文为大学生科技创新院级基金项目(编号:2011070)成果 【作者单位】宋君,吉林农业科技学院信息工程学院;张家爱,吉林农业科技学院信息工程学院教师 本着锻炼自我与积极参与到实用性技术的目标,以发掘自身创新意识为前提。利用空闲时间,在老师的指导下,进行了一次大学生创新项目的实践性活动。本着实用原则,以某中小旅行社为客户(根据用户需求,匿名),以Struts2框架为基点,进行了一次旅行社管理系统的开发。在项目结束之余, 特将在项目过程中经历的种种认识进行了简单的总结,希望让阅读本文的朋友们,更多的参与到此类活动中。 一、基础思想— ——MVC 简述作为时下经典框架之一, MVC 具有其独特的价值。MVC 框架简单的说,就是将数据模型与用户视图进行分离。通过控制器进行协调处理的一种结构是框架。同时,也是本文中要讨论的Sturts2框架的基础思想。 M 是指模型层(Model ),V 是指用户视图(View ),C 则是指控制器 (Controller )。这种划分方式是以将模型层与视图层进行代码分离,从而降低两者之间的耦合性,使同一程序可以使用不同形式进行表现。不同层之间的修改不会或尽量少的印象到其他层功能的史前为前提。有效的提高的代码的维护性和设计难度。 图1 二、 Struts2工作原理(一)Struts2框架组成。Struts2框架由三个主要部分组成:核心控制器、业务控制器,以及由用户实现的业务逻辑组件。这里我们将侧重于核心控制器与业务控制器的理解与说明。 (二)核心控制器:FilterDispatcher 。FilterDispatcher 是Struts2框架的核心控制器,在此,我们可以将FilterDispatcher 看作一个类似于过滤网的过滤器。当用户发出请求,并到达Web 硬哟那种时,该过滤器会过滤用户请求。如果用户请求的结尾为action ,则将该请求转入Struts2框架进行处理。当Struts2框架获得了*.actio 请求后,会根据请求前面“*”的那部分内容,决定调用哪个业务逻辑组件作为响应单位。这里需要说明的是Struts2用来处理用户请求的Action 实例并不是业务控制器,而是作为Action 的代理———正因为Struts2的一大特点,与Servlet API 的非耦合性,使得用户实现的业务控制器无法直接处理用户请求。有效的提高了后期调试维护的效率。而Struts2框架再次提供了了一系列的拦截器。这些拦截器负责将HttpServletRequest 请求的参数解析出来,传入Action 中,并毁掉Action 的Execute 方法来处理用户请求。用户实现的Action 类仅作为Struts2的Action 代理的代理目标。用户实现的业务控制器则包含了对用户请求的处理。用户的请求数据包含在HttpServletRequest 对象中,而用户的Action 类无需访问HttpServletRequest 对象。拦截器负责将HttpServletRequest 里的请求数据解析出来,并传给业务逻辑组件Action 实例。 (三)业务控制器。业务控制器就是前文提到的用来实现用户Action 的实力,这里的每个Action 类通常包含有一个execute 方法,当业务控制器处理完用户的请求后,该方法将会针对此次处理返回一个字符串— ——该字符串就是一个逻辑树图名。当程序开发人员开发出系统所需要的业务控制器后,还需要针对性的配置Struts2的Action ,即需要配置Ac- tion 的以下三个部分:(1)Action 所处理的URl 。(2)Action 组件所对应的实现类。(3)Action 里包含的逻辑试图和物理资源之间的对应关系。每个Action 都要处理一个用户请求,而用户请求则总是包含有指定的URL 。当核心控制器过滤用户请求,并调用后,根据请求的URL 和Action 处理URL 之间的对应关系来处理转发。 · 342·

词法分析器实验报告及源代码

数学与软件科学学院实验报告 学期:13至14__ 第_2 学期 2014年3月17 日 课程名称:编译原理专业:2011级5_班 实验编号:01 实验项目:词法分析器指导教师_王开端 姓名:张世镪学号: 2011060566 实验成绩: 一、目的 学习编译原理,词法分析是编译的第一个阶段,其任务是从左至右挨个字符地对源程序进行扫描,产生一个个单词符号,把字符串形式的源程序改造成单词符号串形式的中间程序。执行词法分析的程序称为词法分析程序,也称为词法分析器或扫描器。词法分析器的功能是输入源程序,输出单词符号 做一个关于C的词法分析器,C++实现 二、任务及要求 1.词法分析器产生下述C的单词序列 这个C的所有的单词符号,以及它们的种别编码和内部值如下表: -* / & <<=>>===!= && || , : ; { } [ ] ( ) ID和NUM的正规定义式为: ID→letter(letter | didit)* NUM→digit digit* letter→a | … | z | A | … | Z

digit→ 0 | … | 9 如果关键字、标识符和常数之间没有确定的算符或界符作间隔,则至少用一个空格作间隔。空格由空白、制表符和换行符组成。 三、大概设计 1. 设计原理 词法分析的任务:从左至右逐个字符地对源程序进行扫描,产生一个个单词符号。 理论基础:有限自动机、正规文法、正规式 词法分析器又称扫描器:执行词法分析的程序 2. 词法分析器的功能和输出形式 功能:输入源程序、输出单词符号 程序语言的单词符号一般分为以下五种:关键字、标识符、常数、运算符、界符。3. 输出的单词符号的表示形式: (单词种别,单词符号的属性值) 单词种别用整数编码,关键字一字一种,标识符统归为一种,常数一种,各种符号各一种。 4. 状态转换图实现

yaffs2文件系统制作

交叉编译器ARM-Linux-gcc4.1.2 开发板TX2440A Busybox-1.15.1.tar.bz2(在Linux中被称为瑞士军刀) mkyaffs2image工具 首先创建一个名字为root_2.6.31的文件夹,在其中创建如下文件夹 etc bin var dev home lib mnt proc root sbin sys tmp usr opt共14个文件夹 解压Busybox tar xjvf busybox 进入源目录,修改Makefile 第164行,CROSS_COMPILE=arm-linux- 第190行,ARCH=arm 执行#make men onfig进行配置 配置选项大部分都是保持默认的,只需要注意选择以下这几个选项,其他的选项都不用动:Busybox Setting---> Build Options---> [*]Build Busybox as a static binary(no shared libs) [*]Build with Large File Support(for accessing files>2GB) Installation Options--->

(./_install)Busybox installation prefix 进入这个选项,输入busybox的安装路径,如:../rootfs Busybox Library Tuning---> [*]vi-style line editing commands [*]Fancy shell prompts 要选择这个选项:“Fancy shell prompts”,否则挂载文件系统后,无法正常显示命令提示符:“[\u@\h\W]#” 配置完成以后 执行#make #make install 然后就会在上一级目录下生成rootfs文件夹,里面包含几个文件夹/bin/sbin/usr linuxrc 把这些文件全部复制到刚建好的root_2.6.31目录下, #cp–rf*../root_2.6.31 在dev目录下,创建两个设备节点: #mknod console c51 #mknod null c13 然后进入自己建立的etc目录 拷贝Busybox-1.15.2/examples/bootfloopy/etc/*到当前目录下。 #cp-r../../busybox-1.15.2/examples/bootfloopy/etc/*./ 包括文件:fstab init.d inittab profile

企业大数据采集、分析与管理系统设计报告(配图版)

企业大数据采集、分析与管理 系 统 设 计 报 告

目录 一、市场需求信息挖掘 (4) 1. 获取市场需求信息 (4) 2. 市场需求信息分析 (4) 二、工厂成本归集 (4) 1. 基于集成化系统的成本数据采集 (4) 2. 产品成本归集和核算 (5) 三、智能车间大数据采集、分析 (8) 1. 制造车间数据采集 (8) 2. 车间整体状态及计划执行情况分析 (11) 四、业务流程审批及进程监控 (11) 1. 业务流程管控 (12) 2. 采购、订单、物料管理与数据分析 (14) 3. 财务分析与统计 (16) 4. 需求、设计、工艺、制造各环节信息管理 (17) 5. 移动端APP (18) 五、质量信息管理与追溯 (18) 1. 质量信息管理 (18) 2. 供应商评价优选 (19) 六、无纸化OA系统及图档管理 (19) 1. 无纸化OA办公系统 (19) 2. 图纸及技术文档安全管理 (20)

企业大数据采集、分析与管理系统设计报告智能制造是制造业转型升级、向中高端制造业迈进的重要举措。离散制造型企业,其本身具有零件种类多、加工工序复杂、生产过程不确定因素众多、工厂透明度不高、部门间存在信息孤岛等特点。本系统从清晰的状态感知、实时数据分析与展示、决策精准执行与审批、全生命周期产品信息管理、无纸化OA及图档管理五大方面着手解决企业痛点,可以实现产品全生命周期生产过程管理、产品成本管理、信息共享管理和项目远程管理,帮助企业打造透明的、全过程可控的、高感知度的、高柔性的智慧工厂。

一、市场需求信息挖掘 1. 获取市场需求信息 市场需求信息能从多方面反映市场活动的方向,是企业指定经营战略、进行市场竞争的重要依据。本系统在每次客户发起询价时,会要求填写详细的需求信息。通过语义网(Semantic Web),对需求信息进行特征抽取和模糊聚类,进行分类存储,并构建适合企业自身的“市场需求指标库”。 2. 市场需求信息分析 将市场信息转化为企业决策,必须经过复杂的数据处理过程。对市场需求信息大数据聚类之后的各簇,建立统一的预测模型,通过时间序列模型、多元线性回归、最小二乘支持向量机等方法,对行业发展趋势做出预测,并将结果进行图表化展示。 二、工厂成本归集 1. 基于集成化系统的成本数据采集 功能:要素耗费的初次分配、生产成本的分配、辅助生产成本的分配、制造费用的分配。 随着信息化的发展,企业采用了基于集成化的成本数据采集方式如图所示,该采集方式将库存管理、财务管理、资源管理和质量管理等系统之间数据传递和采集,获取成本的相关信息。

语法分析器源代码

#include #include #include #define HIGHER 1 #define LOWER -1 #define EQUAL 0 #define TRUE 1 #define FALSE 0 #define OPER_NUM 50 //默认算符数目 #define VN_NUM 50 //默认非终结符数目#define MAX_BUFFER 128 //每行输入行最大长度 #define MAX_GRA_NUM 20 //最大文法数目#define EMPTY -2 //算符优先表初始值,表示这对算符没有优先关系 #define STACK_SIZE 64 typedef struct { char c; //非终极符符号 int firstvt[OPER_NUM]; //firstvt集,保存算符在oper_list中的下标 int fir_n,last_n; int lastvt[OPER_NUM]; }vn_t; int prior_table[OPER_NUM][OPER_NUM]; char oper_list[OPER_NUM]; int oper_num = 0; vn_t vn_list[VN_NUM]; int vn_num = 0; char *grammar[MAX_GRA_NUM][2]; int gra_num = 0; char start_vn; char stack[STACK_SIZE]; int top = 0; void get_input(char *buf); int buf_deal(char* buf); void get_FIRVT_LASTVT(int vn_n);

linux-2.6.18移植

Linux-2.6.18移植 有了我们的交叉编译环境和我们先前学的内核基础知识,下面我们就开始我们的内核移植了,我们所用的是博创的 S3C2410 。 关于 linux-2.6.18.tar.bz2 的下载网站先前我们说过,我们要先到该官方网站上去下载一个全新的内核。 [root@Binnary ~ ]# tar –jxvf linux-2.6.18.tar.bz2 [root@Binnary ~ ]# make mrproper 如果你是新下载的内核,那这一步就不用了。但如果你用的是别人移植好的内核,那最好在编译内核之前先清除一下中间文件,因为你们用来编译内核的交叉编译工具可能不同。 第一步:修改Makefile文件 将 改为 第二步:修改分区设置信息 我们要先在BootLoader中查看相应的分区信息 vivi>help 然后修改内核源码中的分区信息。分区信息文件在 a rch/arm/mach-s3c2410/common-smdk.c 将其中的

改为如下内容:

第三步:内核通过 BootLoader把数据写入NAND Flash,而vivi的ECC效验算法和内核的不同,内核的效验码是由NAND Flash控制器产生的,所以在此必须禁用NAND Flash ECC。所以我们就要修改 drivers/mtd/nand/s3c2410.c 这个文件。将 中的 chip->ecc.mode = NAND_ECC_SOFT ,改为如下 chip->ecc.mode = NAND_ECC_NONE。

只此一处。 第四步:下面是devfs的问题,因为2.6.12内核以后取消了devfs的配置选项,缺少了它内核会找不到mtdblock设备。所以我们需要修改 fs/Kconfig 文件,或者是从2.6.12的fs/Kconfig中拷贝下面几项到2.6.18的fs/Kconfig中去,我们采用修改的方法来完成。 修改 fs/Kconfig支持devfs 。 在Pseudo filesystems 主菜单的最后添加我们所要的内容。 第五步:文件系统的支持 Yaffs 文件系统 YAFFS文件系统简介 YAFFS,Yet Another Flash File System,是一种类似于JFFS/JFFS2的专门为Flash设计 的嵌入式文件系统。与JFFS相比,它减少了一些功能,因此速度更快、占用内存更少。 YAFFS和JFFS都提供了写均衡,垃圾收集等底层操作。它们的不同之处在于: (1)、JFFS是一种日志文件系统,通过日志机制保证文件系统的稳定性。YAFFS仅仅 借鉴了日志系统的思想,不提供日志机能,所以稳定性不如JAFFS,但是资源占用少。 (2)、JFFS中使用多级链表管理需要回收的脏块,并且使用系统生成伪随机变量决定 要回收的块,通过这种方法能提供较好的写均衡,在YAFFS中是从头到尾对块搜索, 所以在垃圾收集上JFFS的速度慢,但是能延长NAND的寿命。 (3)、JFFS支持文件压缩,适合存储容量较小的系统;YAFFS不支持压缩,更适合存 储容量大的系统。 YAFFS还带有NAND芯片驱动,并为嵌入式系统提供了直接访问文件系统的API,用 户可以不使用Linux中的MTD和VFS,直接对文件进行操作。NAND Flash大多采用 MTD+YAFFS的模式。MTD( Memory Technology Devices,内存技术设备)是对Flash 操作的接口,提供了一系列的标准函数,将硬件驱动设计和系统程序设计分开。 Yaffs 文件系统内核没有集成,可以对其主页下载: https://www.360docs.net/doc/ac10915837.html,/cgi-bin/viewcvs.cgi/#dirlist

struts2 实验报告

1.系统分析与设计 1.1 系统功能描述 本系统是个非常简单的注册、登录系统。本系统的实现是基于Struts2、Spring、Hibernate 三个框架,系统功能单一,业务逻辑简单。 当用户注册信用户时,就是向系统中增加一个新用户,对应的数据库增加一条记录。 当用户输入注册信息时,系统提供了基本的输入验证判断用户输入是否合法,只有当用户输入满足基本输入要求时,才会被提交到实际的登录系统,进行实际的登录处理。 系统还使用了随机产生的图形验证码来防止刷新,防止用户通过单击浏览器的书安心按钮来重复注册多个用户。 系统还提供了一种Ajax方式来验证用户输入的注册名是否有效,系统要求所有的用户名不能重复。故当用户输完用户名后,系统立即在页面上方提示用户该用户名是否可用,如果系统中没有该用户名,则系统提示该用户名可用;否则提示用户该用户名重复,用户必须重新选择用户名注册。 当用户注册一个新用户名之后,就可以使用系统的登录功能来登录系统了,用户输入登录用的用户名、密码后,系统一样提供了基本的输入校验。 除此之外,系统还采用了随机产生图形验证码来防止恶意用户的暴力破解,系统随机生成一个图形验证码,而用户登录必须输入图形验证码中显示的字符串,只有用户输入的字符串和系统随机生成的验证码字符相同时,系统才允许用户登录。 1.2 系统功能流程

1.3 数据库设计 相关的映射文件: 一旦提供了上面的映射文件,Hibernate 就可以理解User 和user_table 之间的对应关系。 2.系统实现与测试 2.1 系统采用的关键技术 MVC 框架采用了Struts2框架,Struts2框架的易用性,极好的简化了系统的MVC 层的实现;本系统使用了Struts2的JSON 插件来完成Ajax 功能,除此之外本系统为了避免进行底层的Ajax 交互,还是用了一个简单Prototype.js 函数库,用以简化Ajax 编程。Struts2框架的稳定性,为系统的稳定运行提供了保证。

大数据企业架构讨论

大数据企业架构讨论

案例研究:智慧交通
大数据实时处理和分析
目的:提高城市交通的科学管理和组织服务水平
业务目标
传感 器
? 压力传感器 ? 速度传感器 ? 生物传感器 ? 温度、湿度……
RFID
? 射频天线扫描 ? 电子标识
? 智能交通数据的有力支撑 ? 智能交通公共信息服务的实时传递和快速反 应的应急指挥 ? 智能交通业务联动快速应对变化 ? 可视化事件跟踪
摄像 头
挑战
? 高速拍照 ? 高清摄像头
? 近千万辆轿车、轨道交通、快速公交系统 ? 高并发事件及数据流的实时处理 ? 海量非结构化大数据的组织与分析

智能交通整体规划架构
信息服务
用户服务
政府
企业
公共
个人
ITS智能交通物联网平台
城市综合信息管理平台 铁路综合管理平台 水运综合管理平台
应用层/ 信息处理
公路可视化综合信息平台
公共交通运营管理平台
雷达测速 通信 监控 GIS 信号 电警 车次号识别 ETC CBTC 紧急救援 接处警 卡口 视频监控 PIS 事件检测 交通诱导 BRT 路径识别 信号控制 旅行时间 出行者信息系统 电子站牌 智能停车场 公交调度管理
车地双向实时无线通信网数传电台 政府专网 Internet
网络层/ 信息传输
GPRS/CDMA/3G/Wi-Fi/WiMax光纤TCP/IP
感知层/ 信息采集
交通行业
3

编译原理课程设计-词法分析器(附含源代码)

编译原理-词法分析器的设计 一.设计说明及设计要求 一般来说,编译程序的整个过程可以划分为五个阶段:词法分析、语法分析、中间代码生成、优化和目标代码生成。本课程设计即为词法分析阶段。词法分析阶段是编译过程的第一个阶段。这个阶段的任务是从左到右一个字符一个字符地读入源程序,对构成源程序的字符流进行扫描和分解,从而识别出一个个单词(也称单词符号或符号)。如保留字(关键字或基本字)、标志符、常数、算符和界符等等。 二.设计中相关关键字说明 1.基本字:也称关键字,如C语言中的 if , else , while , do ,for,case,break, return 等。 2.标志符:用来表示各种名字,如常量名、变量名和过程名等。 3.常数:各种类型的常数,如12,6.88,和“ABC” 等。 4.运算符:如 + ,- , * , / ,%, < , > ,<= , >= 等。5.界符,如逗点,冒号,分号,括号,# ,〈〈,〉〉等。 三、程序分析 词法分析是编译的第一个阶段,它的主要任务是从左到右逐个字符地对源 程序进行 扫描,产生一个个单词序列,用以语法分析。词法分析工作可以是独立的一遍,把字符流的源程序变为单词序列,输出在一个中间文件上,这个文件做为语法分析程序的输入而继续编译过程。然而,更一般的情况,常将

词法分析程序设计成一个子程序,每当语法分析程序需要一个单词时,则 调用该子程序。词法分析程序每得到一次调用,便从源程序文件中读入一 些字符,直到识别出一个单词,或说直到下一个单词的第一个字符为止。 四、模块设计 下面是程序的流程图 五、程序介绍 在程序当前目录里建立一个文本文档,取名为infile.txt,所有需要分析的程序都写在此文本文档里,程序的结尾必须以“@”标志符结束。程序结果输出在同一个目录下,文件名为outfile.txt,此文件为自动生成。本程序所输出的单词符号采用以下二元式表示:(单词种别,单词自身的值)如程序输出结果(57,"#")(33,"include")(52,"<")(33,"iostream") 等。 程序的功能:(1)能识别C语言中所有关键字(共32个)(单词种别分别为1 — 32 ,详情见程序代码相关部分,下同) (2)能识别C语言中自定义的标示符(单词种别为 33) (3)能识别C语言中的常数(单词种别为0) (4)能识别C语言中几乎所有运算符(单词种别分别为41 — 54) (5)能识别C语言中绝大多数界符(单词种别分别为 55 — 66)六、运行结果 输入文件infile.txt 运行结果(输出文件 outfile.txt)

Yaffs2文件系统中对NAND Flash磨损均衡的改进

Yaffs2文件系统中对NAND Flash磨损均衡的改进 摘要:针对以NAND Flash为存储介质时Yaffs2文件系统存在磨损均衡的缺陷,通过改进回收块选择机制,并在数据更新中引入冷热数据分离策略,从而改善NAND Flash的磨损均衡性能。实验借助Qemu软件建立Linux嵌入式仿真平台,从总擦除次数、最大最小擦除次数差值和块擦除次数标准差等方面进行对比。实验结果表明,在改进后的Yaffs2文件系统下NAND Flash的磨损均衡效果有明显提升,这有益于延长NAND Flash的使用寿命。 关键词: Yaffs2文件系统;NAND Flash;垃圾回收;冷热数据 0 引言 NAND Flash存储设备与传统机械磁盘相比,具有体积小、存储密度高、随机存储和读写能力强、抗震抗摔、功耗低等特点[1]。它被广泛用于智能手机、车载智能中心、平板电脑等智能终端中。近年来,以NAND Flash为存储介质的固态硬盘也得到越来越多的应用。目前Yaffs2文件系统(Yet Another Flash File System Two,Yaffs2)[1]是使用最多、可移植性最好的专用文件系统,在安卓、阿里云OS、Linux等嵌入式系统中都有使用。在Yaffs2文件系统下以NAND Flash为存储介质时存在磨损均衡的缺陷,可通过对回收块选择机制作改进和引入冷热数据分离策略来提高磨损均衡的效果。 1 Yaffs2和Nand Flash关系 这里以使用最多的Linux操作系统为实践,将Yaffs2文件系统移植到Linux操作系统中。Linux系统通常可以分为3层:应用层、内核层和设备层,其中支持NAND Flash设备的Yaffs2文件系统属于内核层,。 最上层用户应用程序通过VFS(Virtual File System)提供的统一接口,将数据更新等文件操作传递给Yaffs2。VFS代表虚拟文件系统,它为上层应用提供统一的接口。有了这些接口,应用程序只用遵循抽象后的访问规则,而不必理会底层文件系统和物理构成上的差异。然后Yaffs2通过MTD(Memory Technology Device)提供的统一访问接口对NAND Flash进行读、写和擦除操作,从而完成数据的更新或者存储操作。MTD代表内存技术设备,它为存储设备提供统一访问的接口。最终,在NAND Flash上以怎样的格式组织和存储数据由Yaffs2文件系统决定。 NAND Flash由若干块(block)组成,每个块又是由若干页(page)组成,页中含有数据区和附加区。NAND Flash的页根据状态不同,可以分为有效页、脏页、空闲页。有效页中存放有效数据,脏页中存放无效数据,空闲页是经过擦除后可以直接用于写入数据的页。NAND Flash在写入数据前需要执行擦除操作,因此数据不能直接在相同的位置更新。当一个页中数据需要更新时,必须将该页中有效数据拷贝到其他空闲页上再更新,并将原来页上的数据置为无效。随着时间的推移,许多无效页累积在存储器中使得空闲页逐渐减少。当存储器中的空闲空间不足时,启动垃圾回收操作,利用回收块选择机制从待回收块中选取满足要求的块来擦除,从而得到足够的空闲空间。NAND Flash中块的擦除次数有限,通常为10 000次~100 000次[2]。当某个块的擦除次数超过使用寿命时,该块将无法正常用于数据存储。因此,垃圾回收应利用合理的回收块选择机制,从待回收块中找到回收后能产生良好磨损均衡效果且付出较少额外代价的块来回收,从而获得足够的空闲空间用于数据更新操作。 2 Yaffs2在磨损均衡方面的缺陷 Yaffs2中回收块的选择机制[3]是从待回收块中找到有效数据最少的块来回收。回收过程中,Yaffs2能够减少有效数据的额外读和写操作。当数据更新处于均匀分布的情况下,Yaffs2表现出较好的磨损均衡效果。 但是,通常情况下数据的更新频率不同,有些数据经常更新,而有些数据很少更新。经

大数据处理技术的总结与分析

数据分析处理需求分类 1 事务型处理 在我们实际生活中,事务型数据处理需求非常常见,例如:淘宝网站交易系统、12306网站火车票交易系统、超市POS系统等都属于事务型数据处理系统。这类系统数据处理特点包括以下几点: 一就是事务处理型操作都就是细粒度操作,每次事务处理涉及数据量都很小。 二就是计算相对简单,一般只有少数几步操作组成,比如修改某行得某列; 三就是事务型处理操作涉及数据得增、删、改、查,对事务完整性与数据一致性要求非常高。 四就是事务性操作都就是实时交互式操作,至少能在几秒内执行完成; 五就是基于以上特点,索引就是支撑事务型处理一个非常重要得技术. 在数据量与并发交易量不大情况下,一般依托单机版关系型数据库,例如ORACLE、MYSQL、SQLSERVER,再加数据复制(DataGurad、RMAN、MySQL数据复制等)等高可用措施即可满足业务需求。 在数据量与并发交易量增加情况下,一般可以采用ORALCERAC集群方式或者就是通过硬件升级(采用小型机、大型机等,如银行系统、运营商计费系统、证卷系统)来支撑. 事务型操作在淘宝、12306等互联网企业中,由于数据量大、访问并发量高,必然采用分布式技术来应对,这样就带来了分布式事务处理问题,而分布式事务处理很难做到高效,因此一般采用根据业务应用特点来开发专用得系统来解决本问题。

2数据统计分析 数据统计主要就是被各类企业通过分析自己得销售记录等企业日常得运营数据,以辅助企业管理层来进行运营决策。典型得使用场景有:周报表、月报表等固定时间提供给领导得各类统计报表;市场营销部门,通过各种维度组合进行统计分析,以制定相应得营销策略等. 数据统计分析特点包括以下几点: 一就是数据统计一般涉及大量数据得聚合运算,每次统计涉及数据量会比较大。二就是数据统计分析计算相对复杂,例如会涉及大量goupby、子查询、嵌套查询、窗口函数、聚合函数、排序等;有些复杂统计可能需要编写SQL脚本才能实现. 三就是数据统计分析实时性相对没有事务型操作要求高。但除固定报表外,目前越来越多得用户希望能做做到交互式实时统计; 传统得数据统计分析主要采用基于MPP并行数据库得数据仓库技术.主要采用维度模型,通过预计算等方法,把数据整理成适合统计分析得结构来实现高性能得数据统计分析,以支持可以通过下钻与上卷操作,实现各种维度组合以及各种粒度得统计分析。 另外目前在数据统计分析领域,为了满足交互式统计分析需求,基于内存计算得数据库仓库系统也成为一个发展趋势,例如SAP得HANA平台。 3 数据挖掘 数据挖掘主要就是根据商业目标,采用数据挖掘算法自动从海量数据中发现隐含在海量数据中得规律与知识。

如何看懂源代码--(分析源代码方法)

如何看懂源代码--(分析源代码方法) 4 推 荐 由于今日计划着要看Struts 开源框架的源代码 昨天看了一个小时稍微有点头绪,可是这个速度本人表示非常不满意,先去找了下资 料, 觉得不错... 摘自(繁体中文 Traditional Chinese):http://203.208.39.132/translate_c?hl=zh-CN&sl=en&tl=zh-CN&u=http://ww https://www.360docs.net/doc/ac10915837.html,/itadm/article.php%3Fc%3D47717&prev=hp&rurl=https://www.360docs.net/doc/ac10915837.html,&usg=AL kJrhh4NPO-l6S3OZZlc5hOcEQGQ0nwKA 下文为经过Google翻译过的简体中文版: 我们在写程式时,有不少时间都是在看别人的代码。 例如看小组的代码,看小组整合的守则,若一开始没规划怎么看,就会“噜看噜苦(台语)”不管是参考也好,从开源抓下来研究也好,为了了解箇中含意,在有限的时间下,不免会对庞大的源代码解读感到压力。网路上有一篇关于分析看代码的方法,做为程式设计师的您,不妨参考看看,换个角度来分析。也能更有效率的解读你想要的程式码片段。 六个章节: ( 1 )读懂程式码,使心法皆为我所用。( 2 )摸清架构,便可轻松掌握全貌。( 3 )优质工具在手,读懂程式非难事。( 4 )望文生义,进而推敲组件的作用。( 5 )找到程式入口,再由上而下抽丝剥茧。( 6 )阅读的乐趣,透过程式码认识作者。 程式码是别人写的,只有原作者才真的了解程式码的用途及涵义。许多程式人心里都有一种不自觉的恐惧感,深怕被迫去碰触其他人所写的程式码。但是,与其抗拒接收别人的程式码,不如彻底了解相关的语言和惯例,当成是培养自我实力的基石。 对大多数的程式人来说,撰写程式码或许是令人开心的一件事情,但我相信,有更多人视阅读他人所写成的程式码为畏途。许多人宁可自己重新写过一遍程式码,也不愿意接收别人的程式码,进而修正错误,维护它们,甚至加强功能。 这其中的关键究竟在何处呢?若是一语道破,其实也很简单,程式码是别人写的,只有原作者才真的了解程式码的用途及涵义。许多程式人心里都有一种不自觉的恐惧感,深怕被迫去碰触其他人所写的程式码。这是来自于人类内心深处对于陌生事物的原始恐惧。 读懂别人写的程式码,让你收获满满 不过,基于许多现实的原因,程式人时常受迫要去接收别人的程式码。例如,同事离职了,必须接手他遗留下来的工作,也有可能你是刚进部门的菜鸟,而同事经验值够了,升级了,风水轮流转,一代菜鸟换菜鸟。甚至,你的公司所承接的专案,必须接手或是整合客户前一个厂商所遗留下来的系统,你们手上只有那套系统的原始码(运气好时,还有数量不等的文件)。 诸如此类的故事,其实时常在程式人身边或身上持续上演着。许多程式人都将接手他人的程式码,当做一件悲惨的事情。每个人都不想接手别人所撰写的程式码,因为不想花时间去探索,宁可将生产力花在产生新的程式码,而不是耗费在了解这些程式码上。

2-Linux

Linux-2.6.32.2内核在mini2440上的移植(二)---yaffs2文件系统移植 移植环境(红色粗字体字为修改后内容,蓝色粗体字为特别注意内容) 2.1, yaffs2文件系统移植 【1】获取yaffs2 源代码 现在大部分开发板都可以支持yaffs2 文件系统,它是专门针对嵌入式设备,特别是使用nand flash 作为存储器的嵌入式设备而创建的一种文件系统,早先的yaffs 仅支持小页(512byte/page)的nand flash,现在的开发板大都配备了更大容量的nand flash,它们一般是大页模式的(2K/page),使用yaffs2 就可以支持大页的nand flash,下面是yaffs2 的移植详细步骤。 在https://www.360docs.net/doc/ac10915837.html,/node/346可以下载到最新的yaffs2 源代码,需要使用git工具( 安装方法见Git版本控制软件安装与使用),在命令行输入: [root@localhost ~]# cd ./linux-test [root@localhost linux-test]# git clone git://https://www.360docs.net/doc/ac10915837.html,/ya ffs2 Cloning into yaffs2... remote: Counting objects: 6592, done. remote: Compressing objects: 100% (3881/3881), done. remote: Total 6592 (delta 5237), reused 3396 (delta 2642) Receiving objects: 100% (6592/6592), 3.34 MiB | 166 KiB/s, d one. Resolving deltas: 100% (5237/5237), done.

大数据分析及其在医疗领域中的应用-图文(精)

第7期 24 2014年4月10日 计算机教育 ComputerEducation ◆新视点 文章编号:1672.5913(2014)07—0024-06 中图分类号:G642 大数据分析及其在医疗领域中的应用 邹北骥 (中南大学信息科学与工程学院,湖南长沙410083) 摘要:互联网和物联网技术的快速发展给数据的上传与下载带来了前所未有的便利,使得互联网上 的数据量急剧增长,由此产生了针对大数据的存储、计算、分析、处理等新问题,尤其是对大数据的挖掘。文章分析当前大数据产生的背景,阐述大数据的基本特征及其应用,结合医疗领域,论述医疗 大数据分析的目的、意义和主要方法。 关键词:大数据;物联网;医疗;大数据挖掘 1 大数据早已存在,为何现在称之为大

数据时代 计算与数据是一对孪生姐妹,计算需要数据,数据通过计算产生新的价值。数据是客观事 物的定量表达,来自于客观世界并早已存在。例 如,半个世纪前,全球的人口数量就有数十亿,与之相关的数据就是大数据;但是在那个时代,由于技术的局限性,大数据的采集、存储和处理 还难以实现。 互联网时代之前,采集世界各地的数据并让它们快速地进入计算系统几乎是一件不可想象的 事情。20世纪80年代兴起的互联网技术在近30 年里发生了翻天覆地的变化,彻底地改变了人们的工作和生活方式【l】。通过互联网人们不仅可以下载到新闻、小说、论文等各类文字数据,而且可以轻而易举地下载到音乐、图像和视频等多媒体数据,这使得互联网上的数据流量急剧增长。据统计,现在互联网上每分钟流人流出的数 据量达到1 000 PB,即10亿 GBt21。 推动大数据产生的另一个重要因素是物联网技术。近几年发展起来的物联网技 术通过给每个物品贴上标签 并应用RFID等技术实现了

Struts2的工作机制原理分析及实例

Struts2的工作机制分析及实例 一、概述 本章讲述Struts2的工作原理。 读者如果曾经学习过Struts1.x或者有过Struts1.x的开发经验,那么千万不要想当然地以为这一章可以跳过。实际上Struts1.x 与Struts2并无我们想象的血缘关系。虽然Struts2的开发小组极力保留Struts1.x的习惯,但因为Struts2的核心设计完全改变,从思想到设计到工作流程,都有了很大的不同。 Struts2是Struts社区和WebWork社区的共同成果,我们甚至可以说,Struts2是WebWork的升级版,他采用的正是WebWork 的核心,所以,Struts2并不是一个不成熟的产品,相反,构建在WebWork基础之上的Struts2是一个运行稳定、性能优异、设计成熟的WEB框架。 本章主要对Struts的源代码进行分析,因为Struts2与WebWork的关系如此密不可分,因此,读者需要下载xwork的源代码,访问https://www.360docs.net/doc/ac10915837.html,/xwork/download.action即可自行下载。 下载的Struts2源代码文件是一个名叫struts-2.1.0-src.zip的压缩包,里面的目录和文件非常多,读者可以定位到 struts-2.1.0-src\struts-2.0.10\src\core\src\main\java目录下查看Struts2的源文件,如图14所示。 (图14) 二、主要的包和类 Struts2框架的正常运行,除了占核心地位的xwork的支持以外,Struts2本身也提供了许多类,这些类被分门别类组织到不同的包中。从源代码中发现,基本上每一个Struts2类都访问了WebWork提供的功能,从而也可以看出Struts2与WebWork千丝万缕的联系。但无论如何,Struts2的核心功能比如将请求委托给哪个Action处理都是由xwork完成的,Struts2只是在WebWork 的基础上做了适当的简化、加强和封装,并少量保留Struts1.x中的习惯。

Struts2考试题分析

题目1 以下不届丁 Struts2中result 的type 届性() ? A. action B. redirect 题目2 下歹0有关拦截器说法错误的是? 「A.struts 通过拦截器完成执行action 请求处理方法前一系歹U 操作。例如: 数据封装、文件上传、数据校验等 'B.在struts 中,直接访问jsp 页面,struts 将使用默认拦截器栈处理当前 请求。 厂C.在执行action 时,struts 将执行若干拦截器1、2、3,执行action 完成 后,将继续执行拦截器3、2、1 'D.默认情况,在一个action 没有配置拦截器的引用,说明当前action 将不 使用拦截器 题目3 以下哪些是Action 接口提供的返回值? W A A. success ,D B. none C. error 财 D.input 题目4 如果要实现struts2的数据检验功能 广A 普通的Action 类可以实现 C. redirectAction D. dispatcher

「B继承自Action接口的可以实现 面C继承自ActionSupport类可以实现 厂D继承自ActionValidate 类可以实现 题目5 struts2默认的处理结果类型是: ? A.dispatcher ' B.redirect 「C.chain D. forward 题目6 在值栈的上下文Context中,存在一些固定的key表示不同的对象,以下描述正确的是? A. request,表示request作用域的数据 'B.session,表示session 作用域的数据 阿 C.application ,表示application 作用域的数据 * D.parameters ,表示请求参数的所有数据 题目7 以下届丁struts2配置文件中的配置元素是:()多选) A. B. 厂 C. 厂 D.

相关文档
最新文档