您的位置:首页 > 运维架构 > Linux

CentOS6.3 下安装NFS

2013-06-06 15:28 302 查看
hmap

/* A hash map. */

struct hmap {

struct hmap_node **buckets; /* Must point to 'one' iff 'mask' == 0. */

struct hmap_node *one;

size_t mask;

size_t n;

};

/* A hash map node, to be embedded inside the data structure being mapped. */

struct hmap_node {

size_t hash; /* Hash value. */

struct hmap_node *next; /* Next in linked list. */

};

一个struct hmap_node* 的list是由相同hash的hmap_node组成,用*buckets来指向,buckets是struct hmap_node*的指针数组。其中buckets数组的第一个指针初始化存放在struct hmap_node* one里面。mask表示哈希值的取模,通过hash & mask得到hmap_node所在的buckets下标索引。n表示hmap里当前所有struct hmap_node的个数。一般来说,hmap的node个数不应该超过mask的2倍,如果超过了,需要调整mask值。

sset

sset是string的hmap

/* A set of strings. */

struct sset {

struct hmap map;

};

struct sset_node {

struct hmap_node hmap_node;

char name[1];

};

sset_init, sset_destroy, sset_clear, sset_delete,

sset_delete,删除sset的hmap对应的hmap_node,sset_clear对hmap删除所有 hmap_node,sset_destroy删除所有hmap_node之后hmap_destroy整个hash map,sset_init初始化hmap

sset_find__,在sset的hmap中查找name对应的hmap_node

sset_add__,xmalloc一个sset_node结构,调用hmap_insert插入到sset的hmap中

SSET_FOR_EACH_SAFE宏用来遍历sset,SSET_NODE_FROM_HMAP_NODE, SSET_NAME_FROM_HMAP_NODE, SSET_NODE_NAME用来找到sset的某个hmap_node

SSET_FIRST, SSET_NEXT,用来找sset的第一个node, 下一个node

shash

shash和sset基本没啥区别,唯一区别在于sset是一个string的hmap,shash是一个key-value的hmap

struct shash {

struct hmap map;

};

struct shash_node {

struct hmap_node node;

char *name;

void *data;

};

shash的操作和sset基本一致,就不多说了,无非是hmap的操作的封装

simap

这是一个string 2 integer的hmap数据结构

/* A map from strings to unsigned integers. */

struct simap {

struct hmap map; /* Contains "struct simap_node"s. */

};

struct simap_node {

struct hmap_node node; /* In struct simap's 'map' hmap. */

char *name;

unsigned int data;

};

ofpbuf

struct ofpbuf {

void *base; /* First byte of allocated space. */

size_t allocated; /* Number of bytes allocated. */

enum ofpbuf_source source; /* Source of memory allocated as 'base'. */

void *data; /* First byte actually in use. */

size_t size; /* Number of bytes in use. */

void *l2; /* Link-level header. */

void *l3; /* Network-level header. */

void *l4; /* Transport-level header. */

void *l7; /* Application data. */

struct list list_node; /* Private list element for use by owner. */

void *private_p; /* Private pointer for use by owner. */

};

ofpbuf是一种内存管理类,从名字上看,是给openflow protocol用的,可以通过list_node,把很多ofpbuf挂到一个list上,其成员enum ofpbuf_source source表示这段内存的性质,目前定义了3种,

enum ofpbuf_source {

OFPBUF_MALLOC, /* Obtained via malloc(). */

OFPBUF_STACK, /* Un-movable stack space or static buffer. */

OFPBUF_STUB /* Starts on stack, may expand into heap. */

};

OFPBUF_MALLOC表示这段内存是malloc分配的,所以释放的时候要调用free; OFPBUF_STACK表示这段内存是栈空间; OFPBUF_STUB表示这段内存是栈空间,但可能会溢出到堆空间里(我汗。。哥们你搞笑呢?)

ofpbuf_use 基于malloc分配的内存创建一个ofpbuf结构,ofpbuf_use_stack,基于一块栈的内存创建ofpbuf结构,两者都调用了 ofpbuf_use__,该函数把使用的size设置为0,表示这是一段未使用的内存。另一种创建ofpbuf的方式 ofpbuf_use_const,把size设置为allocated的大小,说明内存已经用满。

ofpbuf_init, ofpbuf_uninit,用malloc/free分配释放一块内存

和skb一样,ofpbuf也有类似的指针,ofpbuf->base表示内存的开始位置,ofpbuf->data表示数据包的开始 位置,ofpbuf_end返回base+allocated位置,表示内存的结束位置,ofpbuf_tail返回data+size位置,表示数据的 结束位置。由此,ofpbuf_headroom返回从base到data之间的空间大小,ofpbuf_tailroom返回end到tail之间的空 间大小。

ofpbuf_resize__,为当前数据包预留new_headroom长度的头部空间,和new_tailroom长度的尾部空间。该函数会 重新分配一段内存,大小为size + new_headroom + new_tailroom,把原有数据拷贝到新内存,并相应修改base, data, l2, l3, l4, l7的位置。数据拷贝调用ofpbuf_copy__完成。ofpbuf_trim做相反的操作,把headroom, tailroom截断为0

ofpbuf_prealloc_tailroom/ofpbuf_prealloc_headroom,如果当前headroom/tailroom空间不满足要求,调用ofpbuf_resize__重新分配headroom/tailroom(至少64字节)

ofpbuf_new_with_headroom,分配一段size + headroom大小的内存,之后ofpbuf->data = ofpbuf->base + size

ofpbuf_put_uninit,调用ofpbuf_prealloc_tailroom为内存段保留size大小的tailroom,返回新的tail位置。该函数有多个衍生函数:

ofpbuf_put_zeros,除ofpbuf_put_uninit之外,把tail之后的size大小的内存空间置0; ofpbuf_put,除ofpbuf_put_uninit之外,拷贝一段size大小的数据;

和skb结构体一样,ofpbuf也有push和pull的操作

ofpbuf_push_uninit,调用ofpbuf_prealloc_headroom为内存段保留size大小的headroom,之后 数据往前长占用headroom的size个字节,此时headroom应该为0. 这种行为和skb的push基本一致。ofpbuf_push_zeros, ofpbuf_push为其衍生函数

ofpbuf_pull,把data往后移size个字节,相当于给headroom空出size个字节空间

flow

lib/flow.h lib/flow.c是用户态视角的flow定义,该结构和内核态的sw_flow完全不同,其真正包含了flow的各个field的内容,e.g.

struct flow {

ovs_be64 tun_id; /* Encapsulating tunnel ID. */

struct in6_addr ipv6_src; /* IPv6 source address. */

struct in6_addr ipv6_dst; /* IPv6 destination address. */

struct in6_addr nd_target; /* IPv6 neighbor discovery (ND) target. */

uint32_t skb_priority; /* Packet priority for QoS. */

uint32_t regs[FLOW_N_REGS]; /* Registers. */

ovs_be32 nw_src; /* IPv4 source address. */

ovs_be32 nw_dst; /* IPv4 destination address. */

ovs_be32 ipv6_label; /* IPv6 flow label. */

uint16_t in_port; /* OpenFlow port number of input port. */

ovs_be16 vlan_tci; /* If 802.1Q, TCI | VLAN_CFI; otherwise 0. */

ovs_be16 dl_type; /* Ethernet frame type. */

ovs_be16 tp_src; /* TCP/UDP source port. */

ovs_be16 tp_dst; /* TCP/UDP destination port. */

uint8_t dl_src[6]; /* Ethernet source address. */

uint8_t dl_dst[6]; /* Ethernet destination address. */

uint8_t nw_proto; /* IP protocol or low 8 bits of ARP opcode. */

uint8_t nw_tos; /* IP ToS (including DSCP and ECN). */

uint8_t arp_sha[6]; /* ARP/ND source hardware address. */

uint8_t arp_tha[6]; /* ARP/ND target hardware address. */

uint8_t nw_ttl; /* IP TTL/Hop Limit. */

uint8_t nw_frag; /* FLOW_FRAG_* flags. */

uint8_t reserved[2]; /* Reserved for 64-bit packing. */

};

flow_extract,解析ofpbuf里的skb数据包,并基于skb结构形成flow,其中需要确保skb的线性空间至少要包含tcp头和 之前的所有内容。和flow_extract相反的操作flow_compose,基于一个struct flow构造一个skb数据包的ofpbuf出来

struct flow_wildcards {

ovs_be64 tun_id_mask; /* 1-bit in each significant tun_id bit. */

flow_wildcards_t wildcards; /* 1-bit in each FWW_* wildcarded field. */

uint32_t reg_masks[FLOW_N_REGS]; /* 1-bit in each significant regs bit. */

ovs_be32 nw_src_mask; /* 1-bit in each significant nw_src bit. */

ovs_be32 nw_dst_mask; /* 1-bit in each significant nw_dst bit. */

struct in6_addr ipv6_src_mask; /* 1-bit in each signficant ipv6_src bit. */

struct in6_addr ipv6_dst_mask; /* 1-bit in each signficant ipv6_dst bit. */

struct in6_addr nd_target_mask; /* 1-bit in each significant

nd_target bit. */

ovs_be16 vlan_tci_mask; /* 1-bit in each significant vlan_tci bit. */

ovs_be16 tp_src_mask; /* 1-bit in each significant tp_src bit. */

ovs_be16 tp_dst_mask; /* 1-bit in each significant tp_dst bit. */

uint8_t nw_frag_mask; /* 1-bit in each significant nw_frag bit. */

uint8_t zeros[5]; /* Padding field set to zero. */

};

flow_wildcards用来做flow match的wildcard,wildcard表示匹配任意数值。对于各个mask的bit而言,bit为0表示这位被wildcard,match flow的时候被无视掉,bit 1则表示该bit需要被匹配

flow_wildcards_init_catchall,初始化struct flow_wildcards结构,使得可以匹配任意的flow。可以看出该函数首先把flow_wildcards->wildcards = FWW_ALL,之后设置所有mask为0

flow_wildcards_init_exact,这样初始化的wildcard,不会去wildcard任何的flow中的field or bit,也就是屏蔽wildcard功能。该函数把flow_wildcards->wildcards = 0,之后设置所有mask位为1

flow_wildcards_combine,合并src1, src2两个struct flow_wildcards*,对于flow_wildcards->wildcards,执行 | 操作,对于flow_wildcards其他field,执行 & 操作

flow_zero_wildcards,对flow的每个field,和flow_wildcards的相应field做 & 操作

dynamic-string

/* A "dynamic string", that is, a buffer that can be used to construct a

* string across a series of operations that extend or modify it.

*

* The 'string' member does not always point to a null-terminated string.

* Initially it is NULL, and even when it is nonnull, some operations do not

* ensure that it is null-terminated. Use ds_cstr() to ensure that memory is

* allocated for the string and that it is null-terminated. */

struct ds {

char *string; /* Null-terminated string. */

size_t length; /* Bytes used, not including null terminator. */

size_t allocated; /* Bytes allocated, not including null terminator. */

};

ds类似于c++里的string类

ds_reserve(struct ds* ds, size_t length),调用xrealloc重新分配ds->allocated + MAX(ds->allocated, length)长度的内存,这表明每次ds_reserve,ds至少要增加一倍的长度

ds_put_uninit(struct ds* ds, size_t n),追加ds一个n个字节长度,返回第ds->length + 1个字节的地址

ds_truncate, ds_clear,仅仅修改ds->length的长度即可

ds_put_cstr(struct ds* ds, const char* s),把string s追加到ds尾部

ds_put_format_valist(struct ds* ds, const char* format, va_list args_),把按照format格式和va_list参数的字符串追加到ds尾部

ds_get_line,从文件里循环读字符,遇到EOF或者\n则停止,返回一行的内容

ds_cstr,给ds->string[ds->length] = '\0',返回ds->string

json

/* Type of a JSON value. */

enum json_type {

JSON_NULL, /* null */

JSON_FALSE, /* false */

JSON_TRUE, /* true */

JSON_OBJECT, /* {"a": b, "c": d, ...} */

JSON_ARRAY, /* [1, 2, 3, ...] */

JSON_INTEGER, /* 123. */

JSON_REAL, /* 123.456. */

JSON_STRING, /* "..." */

JSON_N_TYPES

};

json的数据结构如下

/* A JSON array. */

struct json_array {

size_t n, n_allocated;

struct json **elems;

};

/* A JSON value. */

struct json {

enum json_type type;

union {

struct shash *object; /* Contains "struct json *"s. */

struct json_array array;

long long int integer;

double real;

char *string;

} u;

};

struct json_array对应json里的线性数据结构,[], {}, ()都是线性数据结构,但目前只用到[]。可以看到struct json_array是一个struct json* 的数组,大小为n_allocated,长度为n

struct json根据type不同对应的数据结构也不同,struct shash* object对应json dict,struct json_array是线性数组,这两个都是容器结构;剩下的就是integer, real, string了

static struct json *

json_create(enum json_type type)

{

struct json *json = xmalloc(sizeof *json);

json->type = type;

return json;

}

如果创建指定类型的json元素,e.g. json_boolean_create, json_string_create, json_array_create_empty, 都是调用json_create

对于json_array而言,通过json_array_add, json_array_trim, json_array_create来增减元素。对于json_object而言,json_object_put用来添加哈希表的元素。

json_destroy用来释放一个json结构,对于boolean, integer, real而言,只需free(json)即可,对于string还需free(json->u.string),对于object和array复杂 一点,json_destroy_array对于每个element,递归调用json_destroy;json_destroy_object对于哈 希表每个key<->value,递归调用json_destroy,最后释放整个shash占用的内存

json_clone,对于原子数据结构(e.g. integer, real, string)而言,调用json_xxx_create。对于JSON_OBJECT,调用json_clone_object,该函数把老 object的每个元素顺序通过json_object_put到新的object里,对于JSON_ARRAY,调用 json_clone_array,该函数把老array的每个元素放到struct json** elems中,通过json_array_create返回。

json的hash值计算函数如下:

size_t json_hash(const struct json *json, size_t basis)

{

switch (json->type) {

case JSON_OBJECT:

return json_hash_object(json->u.object, basis);

case JSON_ARRAY:

return json_hash_array(&json->u.array, basis);

case JSON_STRING:

return hash_string(json->u.string, basis);

case JSON_NULL:

case JSON_FALSE:

case JSON_TRUE:

return hash_int(json->type << 8, basis);

case JSON_INTEGER:

return hash_int(json->u.integer, basis);

case JSON_REAL:

return hash_double(json->u.real, basis);

case JSON_N_TYPES:

default:

NOT_REACHED();

}

}

json_hash_object,首先对json object的数据结构struct shash进行排序,得到一个struct shash_node*的排序数组nodes,对nodes的每一个元素,循环计算hash值,每次计算的hash值都参与到后续hash值的计算中

static size_t

json_hash_object(const struct shash *object, size_t basis)

{

const struct shash_node **nodes;

size_t n, i;

nodes = shash_sort(object);

n = shash_count(object);

for (i = 0; i < n; i++) {

const struct shash_node *node = nodes[i];

basis = hash_string(node->name, basis);

basis = json_hash(node->data, basis);

}

return basis;

}

json_hash_array和json_hash_object类似,对array每个元素调用json_hash

下面来看json的parse行为, parser器一个个把字符读进来分析,调用json_lex_input函数,该函数根据当前的parse状态决定下一步的行为,目前定义的状态有

enum json_lex_state {

JSON_LEX_START, /* Not inside a token. */

JSON_LEX_NUMBER, /* Reading a number. */

JSON_LEX_KEYWORD, /* Reading a keyword. */

JSON_LEX_STRING, /* Reading a quoted string. */

JSON_LEX_ESCAPE /* In a quoted string just after a "\". */

};

parser会顺序读下面的字符并存到一个dynamic-string结构里,除非遇到非法字符或者结束标记,e.g. 期望读数字结构读到逗号,读到字符串第二个引号,这时会调用json_lex_xxx,表示已经读完了一个json原子结构

json_lex_xxx,用来解析当前dynamic-string的内容,生成一个struct json_token之后,传给json_parser_input,目前的函数有json_lex_keyword,用来parse诸如true, false, null这样的常量,json_lex_number,以及json_lex_string。json_lex_string还要考虑反斜杠后面的特殊字 符,所以会复杂些。

json_parser_input只接受object, array两类json容器开头的json字符串,如果是object,下面会调用json_parser_push_object,进而调用 json_parser_push,如果当前json_parser->stack为空,让 json_parser->stack[0]->json指向新的struct json*,否则调用json_parser_put_value

static void json_parser_put_value(struct json_parser *p, struct json *value)

{

struct json_parser_node *node = json_parser_top(p);

if (node->json->type == JSON_OBJECT) {

json_object_put(node->json, p->member_name, value);

free(p->member_name);

p->member_name = NULL;

} else if (node->json->type == JSON_ARRAY) {

json_array_add(node->json, value);

} else {

NOT_REACHED();

}

}

json_parser_top返回json_parser->stack最上端的struct json*,然后把key, value对存到该json node里面

我们以一个object的json为例,e.g. { "name" : "jerry", "score" : 100 }

假设该json由string传入,json_from_string会调用json_parser_create,生成一个struct json_parser结构,整个string2json的过程都会用到这个结构

/* A JSON parser. */

struct json_parser {

int flags;

/* Lexical analysis. */

enum json_lex_state lex_state;

struct ds buffer; /* Buffer for accumulating token text. */

int line_number;

int column_number;

int byte_number;

/* Parsing. */

enum json_parse_state parse_state;

#define JSON_MAX_HEIGHT 1000

struct json_parser_node *stack;

size_t height, allocated_height;

char *member_name;

/* Parse status. */

bool done;

char *error; /* Error message, if any, null if none yet. */

};

enum json_parse_state parse_state状态代表了整个json解析过程的进展,表示期望的下一个字符,struct json_parser_node* stack是当出现了递归结构时,e.g. object的一个value又是一个object,把老的object压栈,先解析新的object

言归正传,json_from_string下面会调用json_parser_feed,该函数会一个个的读取字符,然后调用 json_lex_input,我们的object第一个字符是{,其json_parser->lex_state初始化后为 JSON_LEX_START, 此时可以得出当前token type为T_BEGIN_OBJECT,据此构造一个struct json_token,传给后续的json_parse_input

struct json_token {

enum json_token_type type;

union {

double real;

long long int integer;

const char *string;

} u;

};

enum json_lex_state {

JSON_LEX_START, /* Not inside a token. */

JSON_LEX_NUMBER, /* Reading a number. */

JSON_LEX_KEYWORD, /* Reading a keyword. */

JSON_LEX_STRING, /* Reading a quoted string. */

JSON_LEX_ESCAPE /* In a quoted string just after a "\". */

};

enum json_parse_state {

JSON_PARSE_START, /* Beginning of input. */

JSON_PARSE_END, /* End of input. */

/* Objects. */

JSON_PARSE_OBJECT_INIT, /* Expecting '}' or an object name. */

JSON_PARSE_OBJECT_NAME, /* Expecting an object name. */

JSON_PARSE_OBJECT_COLON, /* Expecting ':'. */

JSON_PARSE_OBJECT_VALUE, /* Expecting an object value. */

JSON_PARSE_OBJECT_NEXT, /* Expecting ',' or '}'. */

/* Arrays. */

JSON_PARSE_ARRAY_INIT, /* Expecting ']' or a value. */

JSON_PARSE_ARRAY_VALUE, /* Expecting a value. */

JSON_PARSE_ARRAY_NEXT

};

json_parser_input中,初始化的json_parser->parse_state为JSON_PARSE_START,此 时期望接收的token为 { 或者 [ ,由于我们传入了 { , 会知道这是一个object,下面开始准备parse这个object,先把该object入栈,调用json_parser_push_object

json_parser_push_object 调用json_parser_push,即把一个struct json* 入栈到json_parser->stack里面,并把parse_state改为JSON_PARSE_OBJECT_INIT

下面继续json_parser_feed的主循环,下面json_lex_input会解析到开始字符" ,下面会开始连续尝试读取一个字符串,json_lex_input会一直被调用,直到读到结束的" 字符,此时调用json_lex_string,会生成一个T_STRING类型的struct json_token,传给json_parser_input

此时parse_state已经成为了JSON_PARSE_OBJECT_INIT,由于此时token类型不是 } ,代码很tricky的往下走,走到和JSON_PARSE_OBJECT_NAME,此时json_token的类型match到了T_STRING, 此时为json_parser_push_object做准备,把json_parser->member_name 设为这个token->u.string,把json_parser->parse_state设为 JSON_PARSE_OBJECT_COLON,表示期望接收一个冒号字符

下面自然就是读到一个冒号字符了,json_parser_intput会把状态变更为JSON_PARSE_OBJECT_VALUE,继续 json_lex_input的循环,又会解析出一个字符串出来,在进入json_parser_input之后,调用 json_parse_value,因为此时的字符串已经被当做value来处理了。

如果此时value是非容器类型,调用json_xxx_create生成一个struct json,再调用json_parser_put_value把这个json值放入栈顶的json里面。e.g. 如果栈顶是一个JSON_OBJECT,那么把member_name, value 组成的key-value对插入到这个JSON_OBJECT里,如果是一个JSON_ARRAY,那么就追加到数组末尾,最后把parse_state 设为JSON_PARSE_OBJECT_NEXT

下面如果解析到的是, 字符,那么继续key-value对的解析,如果是 } 字符,说明object解析结束,此时调用json_parser_pop,此时这次解析的json结构已经存到了其父亲json的 object/array里,所以此时弹出json_parser_top的struct json*是安全的

byteq
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: