openvswitch datapath 内核态流表创建过程(ovs_flow_cmd_new)
datapath流表更新的入口函数都定义在dp_flow_genl_ops中,流表创建的入口函数是ovs_flow_cmd_new函数,通过该函数,我们可以一窥流表相关信息的建立。
1、ovs_flow_cmd_new函数
static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
{
struct net *net = sock_net(skb->sk);
struct nlattr **a = info->attrs;
struct ovs_header *ovs_header = info->userhdr;
struct sw_flow *flow = NULL, *new_flow;
struct sw_flow_mask mask;
struct sk_buff *reply;
struct datapath *dp;
struct sw_flow_actions *acts;
struct sw_flow_match match;
u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);
int error;
bool log = !a[OVS_FLOW_ATTR_PROBE]; /* Must have key and actions. */
error = -EINVAL;
if (!a[OVS_FLOW_ATTR_KEY]) {
OVS_NLERR(log, "Flow key attr not present in new flow.");
goto error;
}
if (!a[OVS_FLOW_ATTR_ACTIONS]) {
OVS_NLERR(log, "Flow actions attr not present in new flow.");
goto error;
} /* Most of the time we need to allocate a new flow, do it before
* locking.
*/
new_flow = ovs_flow_alloc();
if (IS_ERR(new_flow)) {
error = PTR_ERR(new_flow);
goto error;
} /* Extract key. */
ovs_match_init(&match, &new_flow->key, false, &mask);
error = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],
a[OVS_FLOW_ATTR_MASK], log);
if (error)
goto err_kfree_flow; /* Extract flow identifier. */
error = ovs_nla_get_identifier(&new_flow->id, a[OVS_FLOW_ATTR_UFID],
&new_flow->key, log);
if (error)
goto err_kfree_flow; /* unmasked key is needed to match when ufid is not used. */
if (ovs_identifier_is_key(&new_flow->id))
match.key = new_flow->id.unmasked_key; ovs_flow_mask_key(&new_flow->key, &new_flow->key, true, &mask); /* Validate actions. */
error = ovs_nla_copy_actions(net, a[OVS_FLOW_ATTR_ACTIONS],
&new_flow->key, &acts, log);
if (error) {
OVS_NLERR(log, "Flow actions may not be safe on all matching packets.");
goto err_kfree_flow;
} reply = ovs_flow_cmd_alloc_info(acts, &new_flow->id, info, false,
ufid_flags);
if (IS_ERR(reply)) {
error = PTR_ERR(reply);
goto err_kfree_acts;
} ovs_lock();
dp = get_dp(net, ovs_header->dp_ifindex);
if (unlikely(!dp)) {
error = -ENODEV;
goto err_unlock_ovs;
} /* Check if this is a duplicate flow */
if (ovs_identifier_is_ufid(&new_flow->id))
flow = ovs_flow_tbl_lookup_ufid(&dp->table, &new_flow->id);
if (!flow)
flow = ovs_flow_tbl_lookup(&dp->table, &new_flow->key);
if (likely(!flow)) {
rcu_assign_pointer(new_flow->sf_acts, acts); /* Put flow in bucket. */
error = ovs_flow_tbl_insert(&dp->table, new_flow, &mask);
if (unlikely(error)) {
acts = NULL;
goto err_unlock_ovs;
} if (unlikely(reply)) {
error = ovs_flow_cmd_fill_info(new_flow,
ovs_header->dp_ifindex,
reply, info->snd_portid,
info->snd_seq, 0,
OVS_FLOW_CMD_NEW,
ufid_flags);
BUG_ON(error < 0);
}
ovs_unlock();
} else {
struct sw_flow_actions *old_acts; /* Bail out if we're not allowed to modify an existing flow.
* We accept NLM_F_CREATE in place of the intended NLM_F_EXCL
* because Generic Netlink treats the latter as a dump
* request. We also accept NLM_F_EXCL in case that bug ever
* gets fixed.
*/
if (unlikely(info->nlhdr->nlmsg_flags & (NLM_F_CREATE
| NLM_F_EXCL))) {
error = -EEXIST;
goto err_unlock_ovs;
}
/* The flow identifier has to be the same for flow updates.
* Look for any overlapping flow.
*/
if (unlikely(!ovs_flow_cmp(flow, &match))) {
if (ovs_identifier_is_key(&flow->id))
flow = ovs_flow_tbl_lookup_exact(&dp->table,
&match);
else /* UFID matches but key is different */
flow = NULL;
if (!flow) {
error = -ENOENT;
goto err_unlock_ovs;
}
}
/* Update actions. */
old_acts = ovsl_dereference(flow->sf_acts);
rcu_assign_pointer(flow->sf_acts, acts); if (unlikely(reply)) {
error = ovs_flow_cmd_fill_info(flow,
ovs_header->dp_ifindex,
reply, info->snd_portid,
info->snd_seq, 0,
OVS_FLOW_CMD_NEW,
ufid_flags);
BUG_ON(error < 0);
}
ovs_unlock(); ovs_nla_free_flow_actions_rcu(old_acts);
ovs_flow_free(new_flow, false);
} if (reply)
ovs_notify(&dp_flow_genl_family, &ovs_dp_flow_multicast_group, reply, info);
return 0; err_unlock_ovs:
ovs_unlock();
kfree_skb(reply);
err_kfree_acts:
ovs_nla_free_flow_actions(acts);
err_kfree_flow:
ovs_flow_free(new_flow, false);
error:
return error;
}
2、ovs_flow_tbl_insert函数
/* Must be called with OVS mutex held. */
int ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow,
const struct sw_flow_mask *mask)
{
int err; err = flow_mask_insert(table, flow, mask);
if (err)
return err;
flow_key_insert(table, flow);
if (ovs_identifier_is_ufid(&flow->id))
flow_ufid_insert(table, flow); return 0;
}
3、flow_mask_insert函数
/* Add 'mask' into the mask list, if it is not already there. */
static int flow_mask_insert(struct flow_table *tbl, struct sw_flow *flow,
const struct sw_flow_mask *new)
{
struct sw_flow_mask *mask; mask = flow_mask_find(tbl, new);
if (!mask) {
struct mask_array *ma;
int i; /* Allocate a new mask if none exsits. */
mask = mask_alloc();
if (!mask)
return -ENOMEM; mask->key = new->key;
mask->range = new->range; /* Add mask to mask-list. */
ma = ovsl_dereference(tbl->mask_array);
if (ma->count >= ma->max) {
int err; err = tbl_mask_array_realloc(tbl, ma->max +
MASK_ARRAY_SIZE_MIN);
if (err) {
kfree(mask);
return err;
}
ma = ovsl_dereference(tbl->mask_array);
} for (i = 0; i < ma->max; i++) {
struct sw_flow_mask *t; t = ovsl_dereference(ma->masks[i]);
if (!t) {
rcu_assign_pointer(ma->masks[i], mask);
ma->count++;
break;
}
} } else {
BUG_ON(!mask->ref_count);
mask->ref_count++;
} flow->mask = mask;
return 0;
}
4、flow_key_insert函数
/* Must be called with OVS mutex held. */
static void flow_key_insert(struct flow_table *table, struct sw_flow *flow)
{
struct table_instance *new_ti = NULL;
struct table_instance *ti; flow->flow_table.hash = flow_hash(&flow->key, &flow->mask->range);
ti = ovsl_dereference(table->ti);
table_instance_insert(ti, flow);
table->count++; /* Expand table, if necessary, to make room. */
if (table->count > ti->n_buckets)
new_ti = table_instance_expand(ti, false);
else if (time_after(jiffies, table->last_rehash + REHASH_INTERVAL))
new_ti = table_instance_rehash(ti, ti->n_buckets, false); if (new_ti) {
rcu_assign_pointer(table->ti, new_ti);
call_rcu(&ti->rcu, flow_tbl_destroy_rcu_cb);
table->last_rehash = jiffies;
}
}
5、table_instance_insert函数
static void table_instance_insert(struct table_instance *ti,
struct sw_flow *flow)
{
struct hlist_head *head; head = find_bucket(ti, flow->flow_table.hash);
hlist_add_head_rcu(&flow->flow_table.node[ti->node_ver], head);
}
6、ovs_nla_copy_actions函数
/* 'key' must be the masked key. */
int ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
const struct sw_flow_key *key,
struct sw_flow_actions **sfa, bool log)
{
int err; *sfa = nla_alloc_flow_actions(min(nla_len(attr), MAX_ACTIONS_BUFSIZE));
if (IS_ERR(*sfa))
return PTR_ERR(*sfa); (*sfa)->orig_len = nla_len(attr);
err = __ovs_nla_copy_actions(net, attr, key, sfa, key->eth.type,
key->eth.vlan.tci, log);
if (err)
ovs_nla_free_flow_actions(*sfa); return err;
}
7、__ovs_nla_copy_actions函数
static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
const struct sw_flow_key *key,
struct sw_flow_actions **sfa,
__be16 eth_type, __be16 vlan_tci, bool log)
{
u8 mac_proto = ovs_key_mac_proto(key);
const struct nlattr *a;
int rem, err; nla_for_each_nested(a, attr, rem) {
/* Expected argument lengths, (u32)-1 for variable length. */
static const u32 action_lens[OVS_ACTION_ATTR_MAX + 1] = {
[OVS_ACTION_ATTR_OUTPUT] = sizeof(u32),
[OVS_ACTION_ATTR_RECIRC] = sizeof(u32),
[OVS_ACTION_ATTR_USERSPACE] = (u32)-1,
[OVS_ACTION_ATTR_PUSH_MPLS] = sizeof(struct ovs_action_push_mpls),
[OVS_ACTION_ATTR_POP_MPLS] = sizeof(__be16),
[OVS_ACTION_ATTR_PUSH_VLAN] = sizeof(struct ovs_action_push_vlan),
[OVS_ACTION_ATTR_POP_VLAN] = 0,
[OVS_ACTION_ATTR_SET] = (u32)-1,
[OVS_ACTION_ATTR_SET_MASKED] = (u32)-1,
[OVS_ACTION_ATTR_SAMPLE] = (u32)-1,
[OVS_ACTION_ATTR_HASH] = sizeof(struct ovs_action_hash),
[OVS_ACTION_ATTR_CT] = (u32)-1,
[OVS_ACTION_ATTR_CT_CLEAR] = 0,
[OVS_ACTION_ATTR_TRUNC] = sizeof(struct ovs_action_trunc),
[OVS_ACTION_ATTR_PUSH_ETH] = sizeof(struct ovs_action_push_eth),
[OVS_ACTION_ATTR_POP_ETH] = 0,
[OVS_ACTION_ATTR_PUSH_NSH] = (u32)-1,
[OVS_ACTION_ATTR_POP_NSH] = 0,
};
const struct ovs_action_push_vlan *vlan;
int type = nla_type(a);
bool skip_copy; if (type > OVS_ACTION_ATTR_MAX ||
(action_lens[type] != nla_len(a) &&
action_lens[type] != (u32)-1))
return -EINVAL; skip_copy = false;
switch (type) {
case OVS_ACTION_ATTR_UNSPEC:
return -EINVAL; case OVS_ACTION_ATTR_USERSPACE:
err = validate_userspace(a);
if (err)
return err;
break; case OVS_ACTION_ATTR_OUTPUT:
if (nla_get_u32(a) >= DP_MAX_PORTS)
return -EINVAL;
break; case OVS_ACTION_ATTR_TRUNC: {
const struct ovs_action_trunc *trunc = nla_data(a); if (trunc->max_len < ETH_HLEN)
return -EINVAL;
break;
} case OVS_ACTION_ATTR_HASH: {
const struct ovs_action_hash *act_hash = nla_data(a); switch (act_hash->hash_alg) {
case OVS_HASH_ALG_L4:
break;
default:
return -EINVAL;
} break;
} case OVS_ACTION_ATTR_POP_VLAN:
if (mac_proto != MAC_PROTO_ETHERNET)
return -EINVAL;
vlan_tci = htons(0);
break; case OVS_ACTION_ATTR_PUSH_VLAN:
if (mac_proto != MAC_PROTO_ETHERNET)
return -EINVAL;
vlan = nla_data(a);
if (!eth_type_vlan(vlan->vlan_tpid))
return -EINVAL;
if (!(vlan->vlan_tci & htons(VLAN_TAG_PRESENT)))
return -EINVAL;
vlan_tci = vlan->vlan_tci;
break; case OVS_ACTION_ATTR_RECIRC:
break; case OVS_ACTION_ATTR_PUSH_MPLS: {
const struct ovs_action_push_mpls *mpls = nla_data(a); if (!eth_p_mpls(mpls->mpls_ethertype))
return -EINVAL;
/* Prohibit push MPLS other than to a white list
* for packets that have a known tag order.
*/
if (vlan_tci & htons(VLAN_TAG_PRESENT) ||
(eth_type != htons(ETH_P_IP) &&
eth_type != htons(ETH_P_IPV6) &&
eth_type != htons(ETH_P_ARP) &&
eth_type != htons(ETH_P_RARP) &&
!eth_p_mpls(eth_type)))
return -EINVAL;
eth_type = mpls->mpls_ethertype;
break;
} case OVS_ACTION_ATTR_POP_MPLS:
if (vlan_tci & htons(VLAN_TAG_PRESENT) ||
!eth_p_mpls(eth_type))
return -EINVAL; /* Disallow subsequent L2.5+ set and mpls_pop actions
* as there is no check here to ensure that the new
* eth_type is valid and thus set actions could
* write off the end of the packet or otherwise
* corrupt it.
*
* Support for these actions is planned using packet
* recirculation.
*/
eth_type = htons(0);
break; case OVS_ACTION_ATTR_SET:
err = validate_set(a, key, sfa,
&skip_copy, mac_proto, eth_type,
false, log);
if (err)
return err;
break; case OVS_ACTION_ATTR_SET_MASKED:
err = validate_set(a, key, sfa,
&skip_copy, mac_proto, eth_type,
true, log);
if (err)
return err;
break; case OVS_ACTION_ATTR_SAMPLE: {
bool last = nla_is_last(a, rem); err = validate_and_copy_sample(net, a, key, sfa,
eth_type, vlan_tci,
log, last);
if (err)
return err;
skip_copy = true;
break;
} case OVS_ACTION_ATTR_CT:
err = ovs_ct_copy_action(net, a, key, sfa, log);
if (err)
return err;
skip_copy = true;
break; case OVS_ACTION_ATTR_CT_CLEAR:
break; case OVS_ACTION_ATTR_PUSH_ETH:
/* Disallow pushing an Ethernet header if one
* is already present */
if (mac_proto != MAC_PROTO_NONE)
return -EINVAL;
mac_proto = MAC_PROTO_NONE;
break; case OVS_ACTION_ATTR_POP_ETH:
if (mac_proto != MAC_PROTO_ETHERNET)
return -EINVAL;
if (vlan_tci & htons(VLAN_TAG_PRESENT))
return -EINVAL;
mac_proto = MAC_PROTO_ETHERNET;
break; case OVS_ACTION_ATTR_PUSH_NSH:
if (mac_proto != MAC_PROTO_ETHERNET) {
u8 next_proto; next_proto = tun_p_from_eth_p(eth_type);
if (!next_proto)
return -EINVAL;
}
mac_proto = MAC_PROTO_NONE;
if (!validate_nsh(nla_data(a), false, true, true))
return -EINVAL;
break; case OVS_ACTION_ATTR_POP_NSH: {
__be16 inner_proto; if (eth_type != htons(ETH_P_NSH))
return -EINVAL;
inner_proto = tun_p_to_eth_p(key->nsh.base.np);
if (!inner_proto)
return -EINVAL;
if (key->nsh.base.np == TUN_P_ETHERNET)
mac_proto = MAC_PROTO_ETHERNET;
else
mac_proto = MAC_PROTO_NONE;
break;
} default:
OVS_NLERR(log, "Unknown Action type %d", type);
return -EINVAL;
}
if (!skip_copy) {
err = copy_action(a, sfa, log);
if (err)
return err;
}
} if (rem > 0)
return -EINVAL; return 0;
}
调试信息:
场景一:
流表:
ovs-ofctl add-flow aaa 'table=0, in_port=veth2 actions=push_mpls:0x8847,set_mpls_label:800,resubmit(,10)' -O openflow15
ovs-ofctl add-flow aaa 'table=10, mpls, mpls_label=800 actions=pop_mpls:0x0800,mod_dl_src=fe:22:33:44:55:66,mod_dl_dst=11:22:33:44:55:66,output:veth3' -O openflow15 调试信息:
3月 20 16:18:30 localhost.localdomain kernel: ovs_flow_cmd_new ... ... 3月 20 16:18:30 localhost.localdomain kernel: nla_for_each_nested, type=3, key_len=12
3月 20 16:18:30 localhost.localdomain kernel: nla_for_each_nested, type=1, key_len=-1
3月 20 16:18:30 localhost.localdomain kernel: type: 3, key_len=12
3月 20 16:18:30 localhost.localdomain kernel: OVS_ACTION_ATTR_SET
3月 20 16:18:30 localhost.localdomain kernel: type: 1, key_len=-1
3月 20 16:18:30 localhost.localdomain kernel: OVS_ACTION_ATTR_OUTPUT
3月 20 16:18:30 localhost.localdomain kernel: nla_for_each_nested, type=3, key_len=12
3月 20 16:18:30 localhost.localdomain kernel: nla_for_each_nested, type=1, key_len=-1
3月 20 16:18:30 localhost.localdomain kernel: type: 3, key_len=12
3月 20 16:18:30 localhost.localdomain kernel: OVS_ACTION_ATTR_SET
3月 20 16:18:30 localhost.localdomain kernel: type: 1, key_len=-1
3月 20 16:18:30 localhost.localdomain kernel: OVS_ACTION_ATTR_OUTPUT
3月 20 16:18:30 localhost.localdomain kernel: do_execute_actions, type: 20
3月 20 16:18:30 localhost.localdomain kernel: kernel OVS_ACTION_ATTR_SET_TO_MASKED
3月 20 16:18:30 localhost.localdomain kernel: do_execute_actions, type: 1
3月 20 16:18:30 localhost.localdomain kernel: kernel OVS_ACTION_ATTR_OUTPUT
3月 20 16:18:30 localhost.localdomain kernel: not find ovs flows ... ...
3月 20 16:18:30 localhost.localdomain kernel: queue_userspace_packet ... ...
3月 20 16:18:30 localhost.localdomain kernel: ovs_flow_cmd_new ... ...
场景二:
流表:
ovs-ofctl add-flow aaa 'table=0, in_port=veth2 actions=push_mpls:0x8847,set_mpls_label:800,output:veth3' -O openflow15
ovs-ofctl add-flow aaa 'table=0, in_port=veth4, mpls, mpls_label=800 actions=pop_mpls:0x0800,mod_dl_src=fe:22:33:44:55:66,mod_dl_dst=11:22:33:44:55:66,output:veth5' -O openflow15 调试信息:
3月 20 16:30:27 localhost.localdomain kernel: ovs_flow_cmd_new ... ...
3月 20 16:30:27 localhost.localdomain kernel: nla_for_each_nested, type=9, key_len=12796
3月 20 16:30:27 localhost.localdomain kernel: nla_for_each_nested, type=1, key_len=-1
3月 20 16:30:27 localhost.localdomain kernel: type: 9, key_len=12796
3月 20 16:30:27 localhost.localdomain kernel: OVS_ACTION_ATTR_PUSH_MPLS
3月 20 16:30:27 localhost.localdomain kernel: type: 1, key_len=-1
3月 20 16:30:27 localhost.localdomain kernel: OVS_ACTION_ATTR_OUTPUT
3月 20 16:30:27 localhost.localdomain kernel: nla_for_each_nested, type=9, key_len=12796
3月 20 16:30:27 localhost.localdomain kernel: nla_for_each_nested, type=1, key_len=-1
3月 20 16:30:27 localhost.localdomain kernel: type: 9, key_len=12796
3月 20 16:30:27 localhost.localdomain kernel: OVS_ACTION_ATTR_PUSH_MPLS
3月 20 16:30:27 localhost.localdomain kernel: type: 1, key_len=-1
3月 20 16:30:27 localhost.localdomain kernel: OVS_ACTION_ATTR_OUTPUT
3月 20 16:30:27 localhost.localdomain kernel: do_execute_actions, type: 9
3月 20 16:30:27 localhost.localdomain kernel: kernel OVS_ACTION_ATTR_PUSH_MPLS
3月 20 16:30:27 localhost.localdomain kernel: do_execute_actions, type: 1
3月 20 16:30:27 localhost.localdomain kernel: kernel OVS_ACTION_ATTR_OUTPUT
3月 20 16:30:27 localhost.localdomain kernel: not find ovs flows ... ...
3月 20 16:30:27 localhost.localdomain kernel: queue_userspace_packet ... ...
3月 20 16:30:27 localhost.localdomain kernel: ovs_flow_cmd_new ... ...
3月 20 16:30:27 localhost.localdomain kernel: nla_for_each_nested, type=3, key_len=12
3月 20 16:30:27 localhost.localdomain kernel: nla_for_each_nested, type=10, key_len=4
3月 20 16:30:27 localhost.localdomain kernel: nla_for_each_nested, type=1, key_len=1
3月 20 16:30:27 localhost.localdomain kernel: type: 3, key_len=12
3月 20 16:30:27 localhost.localdomain kernel: OVS_ACTION_ATTR_SET
3月 20 16:30:27 localhost.localdomain kernel: type: 10, key_len=4
3月 20 16:30:27 localhost.localdomain kernel: OVS_ACTION_ATTR_POP_MPLS
3月 20 16:30:27 localhost.localdomain kernel: type: 1, key_len=1
3月 20 16:30:27 localhost.localdomain kernel: OVS_ACTION_ATTR_OUTPUT
3月 20 16:30:27 localhost.localdomain kernel: nla_for_each_nested, type=3, key_len=12
3月 20 16:30:27 localhost.localdomain kernel: nla_for_each_nested, type=10, key_len=4
3月 20 16:30:27 localhost.localdomain kernel: nla_for_each_nested, type=1, key_len=1
3月 20 16:30:27 localhost.localdomain kernel: type: 3, key_len=12
3月 20 16:30:27 localhost.localdomain kernel: OVS_ACTION_ATTR_SET
3月 20 16:30:27 localhost.localdomain kernel: type: 10, key_len=4
3月 20 16:30:27 localhost.localdomain kernel: OVS_ACTION_ATTR_POP_MPLS
3月 20 16:30:27 localhost.localdomain kernel: type: 1, key_len=1
3月 20 16:30:27 localhost.localdomain kernel: OVS_ACTION_ATTR_OUTPUT
3月 20 16:30:27 localhost.localdomain kernel: do_execute_actions, type: 20
3月 20 16:30:27 localhost.localdomain kernel: kernel OVS_ACTION_ATTR_SET_TO_MASKED
3月 20 16:30:27 localhost.localdomain kernel: do_execute_actions, type: 10
3月 20 16:30:27 localhost.localdomain kernel: kernel OVS_ACTION_ATTR_POP_MPLS
3月 20 16:30:27 localhost.localdomain kernel: do_execute_actions, type: 1
3月 20 16:30:27 localhost.localdomain kernel: kernel OVS_ACTION_ATTR_OUTPUT
3月 20 16:30:27 localhost.localdomain kernel: not find ovs flows ... ...
3月 20 16:30:27 localhost.localdomain kernel: queue_userspace_packet ... ...
总结:
以上以mpls封装解封装为例(或push_vlan,pop_vlan,push_nsh,pop_nsh,push_eth,pop_eth等)
从场景一和场景二得出结论:
流表从in到out中间的过程,如果同时存在push和pop动作,ovs会跳过push和pop动作的处理,不会copy到kernel的流表项中
openvswitch datapath 内核态流表创建过程(ovs_flow_cmd_new)的更多相关文章
- SDNLAB技术分享(四):利用ODL下发流表创建VxLAN网络
邓晓涛,当前就职于江苏省未来网络创新研究院,是CDN团队的一名研发人员,主要从事SDN相关的研发相关工作.曾就职于三星电子于先行解决方案研发组任高级工程师.思科系统于云协作应用技术部(CCATG)任工 ...
- Openvswitch原理与代码分析(6):用户态流表flow table的操作
当内核无法查找到流表项的时候,则会通过upcall来调用用户态ovs-vswtichd中的flow table. 会调用ofproto-dpif-upcall.c中的udpif_upcall_hand ...
- linux内核学习之六 进程创建过程学习
一 关于linux进程概念的补充 关于进程的基本概念这里不多说,把自己的学习所得作一些补充: 1. 在linux内核中,系统最多可以有64个进程同时存在. 2.linux进程包含的关键要素:一段可执行 ...
- 《Linux内核分析》 week6作业-Linux内核fork()系统调用的创建过程
一.进程控制块PCB-stack_struct 进程在操作系统中都有一个结构,用于表示这个进程.这就是进程控制块(PCB),在Linux中具体实现是task_struct数据结构,它主要记录了以下信息 ...
- OVS 内核KEY值提取及匹配流表代码分析
原文链接:http://ry0117.com/2016/12/24/OVS内核KEY值提取及匹配流表代码分析/ 当开启OVS后,创建datapath类型为system的网桥并他添加相关接口,OVS网桥 ...
- ovs源码阅读--流表查询原理
背景 在ovs交换机中,报文的处理流程可以划分为一下三个步骤:协议解析,表项查找和动作执行,其中最耗时的步骤在于表项查找,往往一个流表中有数目巨大的表项,如何根据数据报文的信息快速的查找到对应的流表项 ...
- Openvswitch原理与代码分析(5): 内核中的流表flow table操作
当一个数据包到达网卡的时候,首先要经过内核Openvswitch.ko,流表Flow Table在内核中有一份,通过key查找内核中的flow table,即可以得到action,然后执行acti ...
- Linux操作系统学习_用户态与内核态之切换过程
因为操作系统的很多操作会消耗系统的物理资源,例如创建一个新进程时,要做很多底层的细致工作,如分配物理内存,从父进程拷贝相关信息,拷贝设置页目录.页表等,这些操作显然不能随便让任何程序都可以做,于是就产 ...
- postgres创建表的过程以及部分源码分析
背景:修改pg内核,在创建表时,表名不能和当前的用户名同名. 首先我们知道DefineRelation此函数是最终创建表结构的函数,最主要的参数是CreateStmt这个结构,该结构如下 typede ...
随机推荐
- 将对象转为json,加入到HttpResponseMessage中
需要引用程序集: System.Net.Http System.Web System.Web.Extensions Code: using System; using System.Collectio ...
- 一个新的threejs理论基础学习网站
网站: https://webglfundamentals.org/
- OpenGLES.APPLE_texture_format_BGRA8888
OpenGL ES的扩展: APPLE_texture_format_BGRA8888 http://www.khronos.org/registry/gles/extensions/APPLE/AP ...
- send发送一次buffer
发送的字符串后面添加:\r\n 结束标志 否则发送1024或者程序接收默认的字节数 #include <stdio.h> #include <stdlib.h> #includ ...
- jQuery使用大全
我的程序人生 提供基于Lesktop的IM二次开发,联系QQ:76159179 CnBlogs Home New Post Contact Admin Rss Posts - 476 Article ...
- 我们在地址栏中输入一个网址,比如百度(www.baidu.com)后浏览器做了哪些事
在浏览器输入网址,Enter之后发生的事情: 1. 浏览器接收域名 2. 发送域名给DNS,中文名字是域名系统服务器,一般位于ISP(互联网服务提供商,比如我们熟知的联通.移动.电信等) 中.浏览器会 ...
- JavaScript 静态方法和实例方法
总结: 直接定义在构造函数上的方法和属性是静态的, 定义在构造函数的原型和实例上的方法和属性是非静态的 静态方法: function ClassA(){ //定义构造函数 }; ClassA.fun ...
- 2018.09.19 atcoder AtCoDeer and Rock-Paper(贪心)
传送门 sb贪心啊. 显然能选帕子就选帕子. 首先假设第一个人全出石头. 考虑把一些石头修改成帕子. 这样贡献只增不减,加起来就是答案. 代码: #include<bits/stdc++.h&g ...
- 2018.08.18 NOIP模拟 game(数位dp)
Game 题目背景 SOURCE:NOIP2015-SHY4 题目描述 Alice 和 Bob 正在玩一个游戏,两个人从 1 轮流开始报数,如果遇到 7 的倍数或者遇到的这个数的十进制表示中含 7 , ...
- Python学习网站
Python Website: https://www.python.orgSource code: https://github.com/python/cpython Issue tracker: ...