OVS主线流程

OVS是open virtual switch的简称,是现在广泛使用的软件实现的虚拟网络交换机。

各大云厂商普遍使用OVS来实现自身的虚拟网络,各厂商会根据自身需要加以修改使之符合自身需求,DPU中也使用OVS来实现流表的offload。OVS中的流表基于多级结构,与用户强相关的是opwnflow,下发的流表称为emc flow。

OVS一般存在两种运行模式,内核模式和DPDK模式。内核模式下存在一个datapath的内核模块,模块会在内核层面维护一份emc flow,数据包从网卡接收到时首先在datapath中进行emc flow的匹配,如果无匹配结果,则通过upcall机制交由核心组件ovs-vswitchd处理。ovs-vswitchd收到upcall的数据包时首先根据数据包查询是否存在emc flow,如果存在则根据emc flow的内容对数据包处理,如果不存在则对数据包匹配openflow并根据匹配结果创建emc flow,并将其下发至datapath中,这一过程也称为offload。ovs-vswitchd主要工作就是对收到的数据包进行匹配,根据匹配结果对数据包进行处理并转发。

关于OVS的整体结构,openflow的结构等会另开文章详细介绍,本文主要分析的内容就是OVS的核心组件ovs-vswitchd的整体代码结构,由于该组件结构十分复杂,数据结构也比较多,故此文章会随时间的推移不断的更新,如果有不足之处请各位评论留言。

代码结构简单时,通过缩进的方式表示各function的隶属关系;代码结构复杂时,则通过层级编号+缩进的方式表示。

ovs-vswitchd的主函数

main()->bridge_init()->lacp_init() //命令注册->bond_init() //命令注册->......->ovs_numa_init()->while true //无线循环执行->memory_run() //内存处理->memory_init()->bridge_run() //网桥处理->netdev_run() //网络设备->memory_wait()->bridge_wait()->netdev_wait()

bridge_run()

该func是主要处理数据包的,结构比较复杂,会拆分比较细致

bridge_run()->ovsdb_idl_run() // 连接ovsdb->if_notifier_run()->rtnetlink_run()->nln_run() //通过netlink获取interface变化情况->ovsrec_open_vswitch_first() //获取ovsdb配置->dpdk_init()->bridge_init_ofproto() //初始化网桥上的openflow->bridge_run__()->ofproto_enumerate_types() //ofproto_class目前只有ofproto_dpif,故枚举的就是dpif_classes中的类型,目前是system/netlink和netdev->ofproto_type_run() //执行ofproto_dpif->type_run()->ofproto_run() //对于每一个网桥,执行该func->bridge_reconfigure() //网桥信息重新配

dpdk_init()

dpdk_init()->dpdk_init__()->construct_dpdk_args() //dpdk参数->rte_eal_init()->netdev_dpdk_register() //->netdev_register_flow_api_provider() //调用该函数的有tc,dpdk,dummy

bridge_init_ofproto()

bridge_init_ofproto()-> 判断initialized,该func只执行一次-> //根据cfg配置,先遍历一遍网桥,获取bridge和port结构,放在iface_hints里面->ofproto_init() //对iface_hints的处理->ofproto_class_register(&ofproto_dpif_class) // 注册dpif类型的ofproto_class,存放在ofproto_classes结构体,n_ofproto_classes记录数量,结构体会自己扩容->iface_hints的结构存成init_ofp_ports->ofproto_classes[i]->init(init_ofp_ports) //执行ofproto_class的init,这里是ofproto_dpif_class->ofproto_unixctl_init() //注册一些命令// +1
init() // ofproto_dpif_class-> // 传入的参数添加到init_ofp_ports中->ofproto_unixctl_init/ofproto_dpif_trace_init/udpif_init() // 注册一些unixctl接口// +2
ofproto_unixctl_init()->//注册ofproto_unixctl_dpif_dump_flows->ofproto_dpif_lookup_by_name() // 根据网桥名称查找->unixctl_command_reply() // 往conn写即为回复信息
bridge_run->ofproto_enumerate_types()

ofproto_enumerate_types()

ofproto_enumerate_types()->ofproto_classes[i]->enumerate_types // 以ofproto_dpif_class为例->dp_enumerate_types() 

ofproto_type_run()

ofproto_type_run() // ofproto_dpif->ofproto_normalize_type()->ofproto_class_find__()->ofproto_class->type_run()
type_run()
type_run() // ofproto_dpif->shash_find_data() // 找到dpif_backer->dpif_run() // 执行成功之后,need_revalidate需要置位->dpif->dpif_class->run()  //dpif_netdev_run->udpif_run() // upcall dpif,unixctl消息处理-> // 特定条件下开启从datapath收包->dpif_recv_set()->need_revalidate需要置位->udpif_set_threads()->udpif_start_threads()->ovs_thread_create(udpif_upcall_handler)->ovs_thread_create(udpif_revalidator)->backer->need_revalidate  //需要重新生效 下面有
dpif_netdev_run()
// 4
dpif_netdev_run()->dp_netdev_process_rxq_port() //收,解释下面有->dp_netdev_pmd_flush_output_packets() //发->reconfigure_datapath() // 后面还有解释->reconfigure_pmd_threads() //根据port变化,动态变更线程->ovs_thread_create(pmd_thread_main) // 线程创建->pmd_thread_main() //里面有个无线循环在收和发->ovs_numa_thread_setaffinity_core() //CPU亲和性设定->dp_netdev_process_rxq_port() //处理收->cycle_timer_start() //记录处理时间->dp_packet_batch_init() //batch结构初始化->netdev_rxq_recv() //收->dp_netdev_input() //处理,此处的pkt metadata是无效的->dp_netdev_input__()->dp_netdev_pmd_flush_output_packets()->dp_netdev_pmd_flush_output_packets() //发// 5
dp_netdev_input__() //包处理->dfc_processing() // datapath flow cache,针对每个包的处理->parse_tcp_flags() // flow director找到对应的flow,然后会解析数据包的2 3 4层信息,tcp标签->dp_netdev_queue_batches() // 根据解析出的数据表信息,放入batch里面或者flow map里面->packet_batch_per_flow_init()->packet_batch_per_flow_update()->packet_enqueue_to_flow_map()->miniflow_extract() //提取miniflow ->emc_lookup()->netdev_flow_key_equal_mf() //匹配flow,就是memcmp->fast_path_processing()->dp_netdev_pmd_lookup_dpcls()->dpcls_lookup()->dp_netdev_pmd_lookup_flow()->handle_packet_upcall()->dp_netdev_upcall() // 传入两个action,一个是正常的流表中的,一个貌似是被解析过的->odp_flow_key_from_flow()->dp_netdev->upcall_cb() //netdev有,是通过注册设置的func,在下面有详细解释->dp_netdev_execute_actions() //执行各action,最后可能会将数据包放到队列,下面有详细解释->dp_netdev_pmd_lookup_flow()->dp_netdev_flow_add() // 插入dp_netdev_flow->dp_netdev_pmd_find_dpcls()->dpcls_insert()->dpcls_find_subtable()->dpcls_create_subtable()->dp_emc_flow_add() // 移动->queue_netdev_flow_put()->dp_netdev_queue_batches()->packet_batch_per_flow_execute()->dp_netdev_execute_actions() //下面有详细解释->dp_emc_flow_add()->queue_netdev_flow_put() //解释下面有// 6
dpcls_lookup()->//rules重置->遍历cls->subtables->subtable->lookup_func() //这个比较复杂,需要随后熟悉->//计算为了这个包匹配所做的子表的检索的次数,此举是为了估算每个匹配包的子表的离散程度->//全部匹配了,早点返回// 6
dp_netdev_pmd_lookup_flow()->dp_netdev_pmd_lookup_dpcls()->dpcls_lookup()->dp_netdev_flow_cast()
// 6
queue_netdev_flow_put() //上面有用到->ovs_thread_create(dp_netdev_flow_offload_main)->dp_netdev_alloc_flow_offload()->dp_netdev_append_flow_offload() //插入dp_flow_offload这个list中 
udpif_upcall_handler()
// 4
udpif_upcall_handler() //线程->recv_upcalls()->dpif_recv()->dpif->dpif_class->recv() //netdev没有, netlink有->upcall_receive() //一般会进入这里,匹配流miss->pkt_metadata_from_flow() // 从struct flow的信息回填到pkt metadata->process_upcall() //解释下面有->handle_upcalls()->ukey_install()->dpif_operate()->dpif->dpif_class->operate()   // dpif_netdev_operate?// 5
dpif_netdev_operate()->dpif_netdev_flow_put()->flow_put_on_pmd()->dp_netdev_flow_add()->dpif_netdev_flow_del()->flow_del_on_pmd()->dp_netdev_pmd_remove_flow()->dpif_netdev_execute()->dp_netdev_execute_actions()->odp_execute_actions(dp_execute_cb) //某个OVS_ACTION_XXX会去调用dp_execute_cb->dp_execute_cb() //分OVS_ACTION_XXX进行处理->dp_netdev_pmd_flush_output_on_port()/dp_packet_batch_add() //OVS_ACTION_OUTPUT时,要么发出,要么放到发送对列->push_tnl_action() //OVS_ACTION_ATTR_TUNNEL_PUSH->netdev_push_header() //头部添加->conntrack_execute()->ipf_preprocess_conntrack() //ip分片预处理->write_ct_md()->process_one_fast() //这里会处理nat->handle_nat()->un_nat_packet() / nat_packet()->process_one() //下面有->dp_netdev_pmd_flush_output_packets() //其他地方有详情// 6
dp_netdev_flow_offload_main() //处理dp_flow_offload这个list中的请求->dp_netdev_flow_offload_put()->netdev_flow_put()->flow_api->flow_put() // netdev_offload_dpdk_flow_put
// 7
netdev_offload_dpdk_flow_put()->netdev_offload_dpdk_validate_flow()->netdev_offload_dpdk_add_flow()->netdev_offload_dpdk_actions()->netdev_offload_dpdk_mark_rss()->ufid_to_rte_flow_associate()
// 6
ipf_preprocess_conntrack() //ip分片预处理->ipf_extract_frags_from_batch() // 从batch的一堆包里提取出分片的包,->ipf_is_valid_v4_frag()/ipf_is_valid_v6_frag() //检查是否是有效的ip分片->ipf_handle_frag()  //处理成功之后,添加到ipf里面,并从batch里面删除,不成功refill到batch里面->ipf_v6_key_extract()/ipf_v4_key_extract() //提取ipf key,根据key查找一个ipf list->ipf_process_frag()->ipf_execute_reass_pkts()->ipf_dp_packet_batch_add()
// 6
process_one() //执行之前->initial_conn_lookup()->如果已经是natted过的,conn_key_reverse() //数据包已经被nat了,源、目的IP port更换->conn_key_lookup() //查询conn->//方向错误,且可以强制,则删除->conn_lookup()->conn_clean()->//conn存在且类型是unnat的->conn_key_hash()->conn_key_lookup()->write_ct_md()->conn_update_state()->->//有nat信息且不是新创建的conn->handle_nat->//需要创建新的连接->conn_not_found()->//包不允许创建新conn,退出->//pkt->md.ct_state修改ct_state为 CS_NEW->//需要提交,即正式创建conntrack->//zone限制,直接返回->//数量限制,直接返回->//新建一个conn,设置主动发起的conn的key和rev_key->//有nat信息->//创建nat conn->//选ip和port,可nat的ip和port资源耗尽,退出->nat_packet() //对packet做nat处理->//对packet做nat处理,nat_conn的key是nc的rev_key,反之也是,key里的地址是转换后的->nat_conn->conn_type = CT_CONN_TYPE_UN_NAT; //这里表示要nat还原->//nat_conn也会插入ct->conns->nc->nat_conn = nat_conn; //如果没有nat,则nc->nat_conn是空的->nc->conn_type = CT_CONN_TYPE_DEFAULT; //正常的连接->write_ct_md() // 只有这一处填写packet metadata的地方
udpif_revalidator()
// 4
udpif_revalidator() //线程->revalidate()->revalidator_sweep()->revalidator_sweep__()// 5
revalidator_sweep__()->push_ukey_ops()->push_dp_ops()->ukey_delete()->ukey_delete__()
// 5
revalidate()->dpif_flow_dump_thread_create()->dpif_emc_flow_dump_next() // 移动版本加的->dpif->dpif_class->emc_flow_dump_next() // dpif_netdev_emc_flow_dump_next->dpif_flow_dump_next()->dpif->dpif_class->flow_dump_next() // dpif_netdev_flow_dump_next->ukey_acquire()->ukey_create_from_dpif_flow() // 不推荐在此创建ukey,见代码中注释->ukey_install__()->revalidate_ukey()->revalidate_ukey__()->xlate_ukey()->xlate_push_stats()->reval_op_init()->push_dp_ops()// 6
dpif_netdev_emc_flow_dump_next->dp_netdev_pmd_get_next->cmap_next_position->dpif_emc_flow_timeout->dpif_dp_flow_del_by_emc->dp_pmd_remove_flow_by_emc
// 6
dpif_netdev_flow_dump_next->dp_netdev_pmd_get_next->cmap_next_position(pmd->flow_table)->dp_netdev_flow_to_dpif_flow->get_dpif_emc_flow_status_by_dp_flow
get_dpif_emc_flow_status_by_dp_flow->get_dpif_emc_flow_status
dp_emc_flow_to_dpif_flow->get_dpif_emc_flow_status
get_dpif_emc_flow_status->dpif_netdev_get_emc_flow_offload_status->netdev_ports_get->netdev_emc_flows_get->flow_api->emc_flows_get // netdev_offload_dpdk_emc_flows_get->dp_emc_flow_set_last_stats_attrs->dp_emc_flow_get_last_stats_attrs
netdev_offload_dpdk_emc_flows_get->netdev_dpdk_rte_flow_query_count->rte_flow_query// 6
push_dp_ops()->dpif_operate()->transition_ukey()->xlate_push_stats()->xlate_push_stats_entry()->xlate_push_stats_entry()->rule_dpif_credit_stats()
backer->need_revalidate()
// 4
backer->need_revalidate->//将当前tnl_backers->tnl_backers缓存到tmp_backers->每个ofproto类型 //其实只有ofproto_dpif,且需要backer一致->每个ofport_dpif->//非tnl port跳过->netdev_vport_get_dpif_port() // 貌似是tunnle的话才是vport?->//tmp_backers中有,从中移除,添加到backer->tnl_backers->//tmp_backers中没有->dpif_port_add() //添加到backer->dpif,分配一个odp_port_t出来->dpif_class->port_add()->tnl_port_reconfigure()->dpif_port_del() //删掉tmp_backers中不需要的->xlate_txn_start()->每个ofproto_dpif->xlate_ofproto_set()->每个ofproto_dpif的bundle->xlate_bundle_set()->每个ofproto_dpif的ports->xlate_ofport_set()->xlate_txn_commit()->udpif_revalidate()  //变更序列号// 5
xlate_ofproto_set()->xlate_xbridge_init()->xbridge_addr_create()->xlate_xbridge_set()

ofproto_run()

// 2
ofproto_run()->ofproto_class->run()->bundle_run()->send_pdu_cb()->ofproto_dpif_send_packet()->connmgr_run() // 处理openflow的添加->ofconn_run()->rconn_run()->vconn_run()->vconn_recv()->do_send_packet_ins()->rconn_recv()->vconn_recv()->do_recv()->vconn_stream_recv()->ofptype_decode()->handle_openflow()
// 3
ofproto_dpif_send_packet()->xlate_send_packet()->ofproto_dpif_execute_actions()->ofproto_dpif_execute_actions__()->xlate_actions() //下面有->dpif_execute()->dpif_operate() // 别的地方有
// 3
handle_openflow()->ofptype_decode()->ofpraw_decode()  // 解析成OFPRAW_NXT_FLOW_MOD  OFPRAW_OFPT10_FLOW_MOD  OFPRAW_OFPT11_FLOW_MOD 等 enum ofpraw类型->ofpraw_pull()->ofptype_from_ofpraw() // 从enum ofpraw类型解析成 enum ofptype->raw_info_get()->raw_infos //python生成的结构体->handle_table_features_request()->handle_single_part_openflow()->handle_packet_out() // switch的选项之一->ofproto_packet_out_start()->ofproto->ofproto_class->packet_xlate()->xlate_actions() //下面有->handle_flow_mod() // switch的选项之一->ofputil_decode_flow_mod()->ofpacts_pull_openflow_instructions()->get_actions_from_instruction()->ofpacts_decode()->ofpact_pull_raw()->ofpact_decode_raw()->ofpact_decode() //python生成代码,里面调用decode_XXX->handle_flow_mod__()->ofproto_flow_mod_init() //初始化rule->add_flow_init() // OFPFC_ADD->cls_rule_init_from_minimatch()->ofproto_rule_create()->ofproto->ofproto_class->rule_alloc->rule_actions_create()	//直接就是一块struct ofpact的内存拷贝->ofproto->ofproto_class->rule_construct()->modify_flows_init_loose()  // OFPFC_MODIFY->modify_flow_init_strict() // OFPFC_MODIFY_STRICT->delete_flows_init_loose() // OFPFC_DELETE->rule_criteria_init()->rule_criteria_require_rw()->delete_flows_init_strict() // OFPFC_DELETE_STRICT->ofproto_flow_mod_start() // 开始修改rule->add_flow_start()-> // temp rule是之前add_flow_init时候创建的-> // 从规则中获取到action->rule_from_cls_rule() //查找是否有老规则-> //不存在老规则->choose_rule_to_evict() //超过最大规则数量限制了, 驱逐一条rule-> //存在老规则->rule_collection_add(ofm->old_rules) //添加到老规则列表里->rule_collection_add(ofm->new_rules) // 添加到新规则,上面都是处理ofm这个数据结构->replace_rule_start() // ofproto->tables->cls/刷新rule的有效期->ofproto_rule_insert__()->cookies_insert() //插入到ofproto->cookies->eviction_group_add_rule() //如果rule允许被驱逐,则加入到驱逐列表中->classifier_insert()->classifier_replace()->modify_flow_start_strict()->modify_flows_start__()->replace_rule_start()-> //存在旧规则则移除->ofproto_rule_insert__() //将流插入到原始数据结构中,以便以后的流与之相关。这是可逆的,以防以后的错误需要恢复。->ofproto_flow_mod_finish() // rule修改完成->add_flow_finish()->replace_rule_finish()->ofproto->ofproto_class->rule_insert() //只有old_rule存在时候才做点事情->handle_flow_stats_request()->ofputil_decode_flow_stats_request()->collect_rules_loose()->ofproto->ofproto_class->rule_get_stats->handle_bundle_control()->do_bundle_commit()

bridge_reconfigure()

// 2
bridge_reconfigure()->add_del_bridges()->bridge_delete_ofprotos()->对于all_bridges中的每个bridge->bridge_delete_or_reconfigure_ports()->对于all_bridges中的每个bridge->ofproto_create() //为每个网桥重新配置ofproto信息->对于all_bridges中的每个bridge->bridge_add_ports()->datapath_reconfigure()->对于all_bridges中的每个bridge->对于每一个port->port_configure()// 3
bridge_delete_or_reconfigure_ports()->对于br->ofproto中每个port->netdev_set_config()->netdev->netdev_class->set_config()  //netdev_dpdk_set_config、netdev_dpdk_vdpa_set_config->add_ofp_port() //需要删除的port综合到一起->对于每一个需要删除的port->ofproto_port_del() //这里主要是在dp上删除->遍历每一个port// 4
netdev_dpdk_vdpa_set_config()->netdev_dpdk_set_config()->rte_eth_dev_is_valid_port()->netdev_dpdk_process_devargs()->rte_eth_dev_is_valid_port()->rte_dev_probe()->netdev_dpdk_lookup_by_port_id()// 4
ofproto_port_del()->ofproto->ofproto_class->port_del() // port_del// 5
port_del()->dpif_port_del()->dpif->dpif_class->port_del() // dpif_netdev_port_del// 6
dpif_netdev_port_del()->do_del_port()->reconfigure_datapath()->port_destroy()// 7
reconfigure_datapath() //前面还有一部分解释->对于每一个port->netdev_set_tx_multiq()->对于每一个port->检查是否需要重新配置need_reconfigure->对于每一个需要重配的port->port_reconfigure()->netdev_reconfigure()->netdev_class->reconfigure() // netdev_dpdk_reconfigure、netdev_dpdk_vdpa_reconfigure// 8
netdev_dpdk_vdpa_reconfigure()->netdev_dpdk_reconfigure()->rte_eth_dev_reset()/rte_eth_dev_stop()->netdev_dpdk_mempool_configure()->dpdk_mp_get() // 这里会检查是否有重用之类的->dpdk_mp_create()->设定netdev_dpdk的mempool->dpdk_eth_dev_init()->dpdk_eth_dev_port_config()->rte_eth_dev_info_get()->rte_eth_dev_configure()->rte_eth_dev_set_mtu()->rte_eth_dev_get_mtu()->rte_eth_tx_queue_setup()->rte_eth_rx_queue_setup()->rte_eth_dev_start()->rte_eth_promiscuous_enable()->rte_eth_allmulticast_enable()
// 3
add_del_bridges()->bridge_create()
// 3
ofproto_create() // reconfigure时针对每一个网桥调用,ofproto, ofport的生成->ofproto_normalize_type()->ofproto_class_find__() //找到对应的ofproto类别->class->alloc()->ofproto->ofproto_class->construct() // ofproto class的构造函数
// 4
ofproto_dpif_class->construct()->open_dpif_backer()->shash_add(&all_dpif_backers)->ofproto_init_tables()->hmap_insert(&all_ofproto_dpifs_by_name) //按照名称存ofproto_dpif->hmap_insert(&all_ofproto_dpifs_by_uuid) //按照uuid存ofproto_dpif
// 5
open_dpif_backer()->dpif_create_and_open()->dpif_create()->do_open()->dpif_class->open() //dpif_netdev_open->netdev_open()->netdev_ports_insert()->dpif_open()->do_open()->udpif_create()->dpif_register_upcall_cb(upcall_cb)->dpif_class->register_upcall_cb() //netlink没有,netdev有->check_support()// 6
dpif_netdev_open()->create_dp_netdev()->conntrack_init()// 6
upcall_cb()->upcall_receive() //查找ofproto->classify_upcall() //upcall分类,匹配用户态action,miss或者非法的upcall->xlate_lookup()->xlate_lookup_ofproto_()->//是循环进来的流->recirc_id_node_find() //查询循环信息,没有查到循环信息,跳出->//非无效入口且不是从controller来的()->xport_lookup_by_uuid() //根据port uuid找->//是非循环进来的流->xport_lookup(tnl_port_should_receive, tnl_port_receive)->ofproto_dpif_lookup_by_uuid() // 用户态action upcall->process_upcall()->upcall_xlate() // case选项之一,slow path->//统计->xlate_in_init() /* 默认frozen state是空的,但是当flow的recirc_id不为空,则根据id查找recirc_id_node,然后填充frozen stateodp_actions存放action最终结果 */->xlate_actions()->// 记录为什么进到slowpath里->//用rcu技术将bridge port信息全部存下来->xlate_wc_init() //通配符->tnl_wc_init()->//冻结状态,以下都是冻结状态的恢复->//保留下老的,重新开始trace->//解冻->//已经有规则了,冲突退出?->//ofproto的uuid不匹配->//以frozen state中记录的为准->//没有找到bridge,退出->//没有被跟踪				->clear_conntrack()	->frozen_metadata_to_flow() //恢复frozen state的metadata到flow的metadata->//有栈的话,恢复栈->//恢复镜像状态->//有recirc_id但是不是frozen state,出错了->//获取近似的input port,如果是冻结状态,则flow->in_port是最终的input port->//如果是三层port来的非二层包,添加伪二层信息用于查询->//没有rule和action,查找rule->rule_dpif_lookup_from_table()->rule_dpif_lookup_in_table()->//统计非解冻的包->//不是冻结状态,处理特殊的包,例如lacp,bfd,cfm->mirror_ingress_packet()->//丢弃从预留的镜像端口的包->//除此之外的情况->//没有冻结状态->compose_ipfix_action()->tnl_process_ecn() //action转换开始时候调用,封装丢弃->mirror_ingress_packet() //包镜像->do_xlate_actions()->freeze_unroll_actions() //需要退出,把后续的action给放到ctx->freeze_actions中->// 开启跟踪的话,相关跟踪信息打印上->xlate_output_action() //case的选项之一->xlate_controller_action()/ctx_trigger_freeze() //执行控制器行为或者触发冻结和退出->xlate_group_action() //case的选项之一->compose_conntrack_action() //case的选项之一->compose_slow_path()->ukey_create_from_upcall() // upcall是miss的时候才这么干->ukey_create__()->should_install_flow()->ukey_install()// 7
xlate_output_action()->compose_output_action() //case选项之一,输出到本地、指定端口或者原路返回->compose_output_action__()->check_output_prerequisites() //检查一系列状态->//如果是以太网,则获取三层协议类型->//xport->peer不为空表示是从bridge到bridge的->patch_port_output()->//xport是隧道->netdev_vport_inc_tx() //计数->ovs_native_tunneling_is_on() // 本地隧道和内核隧道->commit_odp_tunnel_action() //额外添加其他的action/* 从一个网桥发到另一个网桥,网桥通过patch port或者tunnel port相连。到另一个网桥的输出action触* 发在下一个网桥中转换的继续。这个过程可以是递归的,下一个网桥还可以发往再下一个。* 从第二个网桥之后的转换了的action在clone action中被封闭,这样任何对包的修改对原本网桥上的剩余action将是可见的 */->xxlate_output_actionlate_commit_actions() // 这里会转换各种set操作->commit_odp_actions()->commit_set_nsh_action()->commit_nsh()->commit_set_nw_action()->commit_set_ipv4_action()->commit_set_ipv6_action()->patch_port_output()->process_special() //process_special处理特殊的协议->native_tunnel_output()->xlate_table_action() //case选项之一,跳转到其他表->rule_dpif_lookup_from_table()->//存下原来的四层源目的地址->//从某个table开始网后找,跳过internal table->//匹配上了,即可退出,没有匹配上,根据系统配置和传入参数综合判断->//未匹配,根据传入参数判断miss之后继续查找或者是发往控制器的话->ofp_port_to_ofport() //从ofproto找到port,该port没有设置no_packet_in,则rule为ofproto->miss_rule->xlate_normal() //case选项之一, 按照内核规则来?->flood_packets() //case选项之一,洪泛->xlate_controller_action() //case选项之一,发往控制器
// 8
native_tunnel_output()->netdev_init_tnl_build_header_params()->tnl_port_build_header()->netdev_build_header()->netdev->netdev_class->build_header() // netdev_vxlan_build_header->odp_put_tnl_push_action()
// 7
xlate_group_action()->// 7
compose_conntrack_action()->xlate_commit_actions()->do_xlate_actions() //内部再次调用do_xlate_actions,解析nat和ct_mark,ct_label信息// 3
bridge_add_ports()->bridge_add_ports__()->iface_lookup()->iface_create()->iface_do_create()->ofproto_port_add()->ofproto->ofproto_class->port_add()
// 4
ofproto->ofproto_class->port_add()->dpif_port_add()->dpif->dpif_class->port_add() //dpif_netdev_port_add->netdev_ports_insert()
// 5
dpif_netdev_port_add()->netdev_vport_get_dpif_port()->do_add_port()->port_create()->netdev_open()->reconfigure_datapath() //前面有解释// 3
port_configure() //ofbundle的生成->ofproto_bundle_register()->bundle_set()

netdev_run()

netdev_run()->netdev_initialize()->netdev_vport_tunnel_register()->netdev_register_provider() //netdev_classes->netdev_class->run() //dpdk netdev_class没有

netdev class之dpdk_class

static const struct netdev_class dpdk_class = {.type = "dpdk",.init = netdev_dpdk_class_init,                     .destruct = netdev_dpdk_destruct,                   .set_tx_multiq = netdev_dpdk_set_tx_multiq,         .get_carrier = netdev_dpdk_get_carrier,             .get_stats = netdev_dpdk_get_stats,                 .get_custom_stats = netdev_dpdk_get_custom_stats,   .get_features = netdev_dpdk_get_features,           .get_status = netdev_dpdk_get_status,               .reconfigure = netdev_dpdk_reconfigure,             .rxq_recv = netdev_dpdk_rxq_recv.construct = netdev_dpdk_construct,.set_config = netdev_dpdk_set_config,.send = netdev_dpdk_send,NETDEV_DPDK_CLASS_COMMON,
};netdev_dpdk_eth_send()->netdev_dpdk_send__()->netdev_dpdk_eth_tx_burst()->rte_eth_tx_burst()netdev_dpdk_rxq_recv()->rte_eth_rx_burst()->dp_packet_batch_init_packet_fields()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/213205.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

变相增大BatchSize——梯度累积

常规训练方式 for x,y in train_loader:pred model(x)loss criterion(pred, label)# 反向传播loss.backward()# 根据新的梯度更新网络参数optimizer.step()# 清空以往梯度,通过下面反向传播重新计算梯度optimizer.zero_grad() pytorch每次forward完都会得到一个…

tidb安装 centos7单机集群

安装 [rootlocalhost ~]# curl --proto https --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh [rootlocalhost ~]# source .bash_profile [rootlocalhost ~]# which tiup [rootlocalhost ~]# tiup playground v6.1.0 --db 2 --pd 3 --kv 3 --host 192.168.1…

按这个套路写的年底工作总结,运维人能少背多少锅?

在职场中,年终工作总结是一项重要的任务,不仅有助于回顾过去一年的工作成果,也为未来设定新的目标提供了参考。在进行年终工作总结的过程中,合理的工作汇报是至关重要的一环。 一、汇报需要坚守的4个法则 01.线索必须单一 观点&am…

js实现元素可拖拽方法

业务需要:Vueelement plus实现对弹框进行拖拽,并可拖拽到显示页面的外面,而element提供的拖拽只能在当前页面不可超出。所以手写了拖拽方法。 实现效果 对元素进行拖拽 拖拽方法 function dragElement(ele) {ele.addEventListener("mous…

SQL自学通之函数 :对数据的进一步处理

目录 一、目标 二、汇总函数 COUNT SUM AVG MAX MIN VARIANCE STDDEV 三、日期/时间函数 ADD_MONTHS LAST_DAY MONTHS_BETWEEN NEW_TIME NEXT_DAY SYSDATE 四、数学函数 ABS CEIL 和FLOOR COS、 COSH 、SIN 、SINH、 TAN、 TANH EXP LN and LOG MOD POW…

【SpringBoot教程】SpringBoot 实现前后端分离的跨域访问(Nginx)

作者简介:大家好,我是撸代码的羊驼,前阿里巴巴架构师,现某互联网公司CTO 联系v:sulny_ann(17362204968),加我进群,大家一起学习,一起进步,一起对抗…

Mybatis之核心配置文件详解、默认类型别名、Mybatis获取参数值的两种方式

学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您: 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持,想组团高效学习… 想写博客但无从下手,急需…

arm-none-eabi-gcc not find

解决办法:安装:gcc-arm-none-eabi sudo apt install gcc-arm-none-eabi; 如果上边解决问题了就不用管了,如果解决不了,加上下面这句试试运气: $ sudo apt-get install lsb-core看吧方正我是运气还不错,感…

leetcode周赛375 - 12 - 10

比赛地址 : 竞赛 - 力扣 (LeetCode) t1 : 直接暴力即可 class Solution { public:int countTestedDevices(vector<int>& b) {int n b.size();int ans 0;for(int i0;i<n;i){if(b[i]>0){ans ;for(int ji1;j<n;j){b[j] max(b[j]-1,0);}}}return ans;} };…

SSL 数字证书的一些细节

参考&#xff1a;TLS/SSL 协议详解(6) SSL 数字证书的一些细节1 证书验证 地址&#xff1a;https://wonderful.blog.csdn.net/article/details/77867063 参考&#xff1a;TLS/SSL协议详解 (7) SSL 数字证书的一些细节2 地址&#xff1a;https://wonderful.blog.csdn.net/articl…

Python学习笔记-类

1 定义类 类是函数的集合&#xff0c;class来定义类 pass并没有实际含义&#xff0c;只是为了代码能执行通过&#xff0c;不报错而已&#xff0c;相当于在代码种占一个位置&#xff0c;后续完善 类是对象的加工厂 2.创建对象 carCar()即是创建对象的过程 3、类的成员 3.1 实例…

福德植保无人机:绿色农业的新篇章

今天&#xff0c;我们荣幸地向您介绍福德植保无人机&#xff0c;一种改变传统农业种植方式&#xff0c;引领绿色农业的新科技产品。福德植保无人机以其高效、环保、安全的特点&#xff0c;正逐渐成为植保行业的新宠。福德植保无人机是一种搭载了高性能发动机和精确喷洒系统的飞…

代码随想录算法训练营第四十六天 _ 动态规划_背包问题总结。

学习目标&#xff1a; 动态规划五部曲&#xff1a; ① 确定dp[i]的含义 ② 求递推公式 ③ dp数组如何初始化 ④ 确定遍历顺序 ⑤ 打印递归数组 ---- 调试 引用自代码随想录&#xff01; 本文大多数内容引用自代码随想录 60天训练营打卡计划&#xff01; 学习内容&#xff1a; …

POJ - 2528 Mayor‘s posters

本题注意离散化的时候可能会出现区间串联情况&#xff0c;比如 [1,10] [5,10] [1,4] 和 [1,10] [6,10] [1,4] 直接离散化的话两者一样&#xff0c;但是实际上是不一样的 解决办法是你在相邻的差不是1的数对中再插一个数就好了 离线区间染色 查询根节点 #include<iostrea…

ASPICE-汽车软件开发能力评级

Automotive SPICE&#xff08;简称A-SPICE 或 ASPICE&#xff09;&#xff0c;全称是“Automotive Software Process Improvement and Capacity dEtermination”&#xff0c;即“汽车软件过程改进及能力评定”模型框架。 常被用于评估一家汽车软件供应商的软件开发能力&#x…

数组|73. 矩阵置零 48. 旋转图像

73. 矩阵置零 **题目:**给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 题目链接&#xff1a;矩阵置零 class Solution {public void setZeroes(int[][] matrix) {Stack<int[]> mapofzerone…

【Python必做100题】之第三题(找出100以内的奇数并打印)

思路&#xff1a; 1、定义一个空列表来存储所有的奇数 2、判断是奇数就追加到列表的末尾 3、打印所有的奇数 代码如下&#xff1a; list [ ] #定义一个列表来存储所有的奇数 for i in range (1,100):if i % 2 ! 0: #判断是否为奇数list.append(i) #追加到列表的末尾 prin…

使用draw.io如何让矩形单个边框有颜色其余边框为空白?

方法步骤: 第一步&#xff1a;用户打开Draw.io软件&#xff0c;并来到流程图的编辑页面上&#xff1b; 第二步&#xff1a;接着在左侧的图形库中点击矩形选项&#xff0c;成功将其添加到流程图的绘制页面上&#xff1b; 第三步&#xff1a;这时用户点击矩形并在右侧窗口中点…

C++ //习题2.3 写出以下程序运行结果。请先阅读程序,分析应输出的结果,然后上机验证。

C程序设计 &#xff08;第三版&#xff09; 谭浩强 习题2.3 习题2.3 写出以下程序运行结果。请先阅读程序&#xff0c;分析应输出的结果&#xff0c;然后上机验证。 #include <iostream> using namespace std;int main(){char c1 a, c2 b, c3 c, c4 \101, c5 \116…

DL Homework 10

习题6-1P 推导RNN反向传播算法BPTT. 习题6-2 推导公式(6.40)和公式(6.41)中的梯度 习题6-3 当使用公式(6.50)作为循环神经网络的状态更新公式时&#xff0c; 分析其可能存在梯度爆炸的原因并给出解决方法&#xff0e; 当然&#xff0c;因为我数学比较菜&#xff0c;我看了好半…