https://github.com/opencomputeproject/SAI
The Switch Abstraction Interface defines the API to provide a vendor-independent way of controlling forwarding elements, such as a switching ASIC, an NPU or a software switch in a uniform manner.
简单理解,SAI是对转发芯片进行一层功能抽象,SDK为每个模块(如VLAN/PORT/FDB等)提供一组函数集,API通过函数集调用SDK接口从而实现转发面的配置管理;另外实现了一套事件处理回调处理。
不足之处:
1)转发芯片功能抽象不稳定,导致接口或参数频繁变化
2)无协议报文处理模块
3)事件处理功能不完整
4)函数集居然不是注册方式
1、main(saiserver.cpp)
1)创建转发芯片:create_switch
sai_api_query(SAI_API_SWITCH, (void**)&sai_switch_api);
attr[0].id = SAI_SWITCH_ATTR_INIT_SWITCH;
attr[0].value.booldata = true;
attr[1].id = SAI_SWITCH_ATTR_SWITCH_STATE_CHANGE_NOTIFY;
attr[1].value.ptr = reinterpret_cast<sai_pointer_t>(&on_switch_state_change); //注册事件处理函数
attr[2].id = SAI_SWITCH_ATTR_SHUTDOWN_REQUEST_NOTIFY;
attr[2].value.ptr = reinterpret_cast<sai_pointer_t>(&on_shutdown_request);
attr[3].id = SAI_SWITCH_ATTR_FDB_EVENT_NOTIFY;
attr[3].value.ptr = reinterpret_cast<sai_pointer_t>(&on_fdb_event);
attr[4].id = SAI_SWITCH_ATTR_PORT_STATE_CHANGE_NOTIFY;
attr[4].value.ptr = reinterpret_cast<sai_pointer_t>(&on_port_state_change);
attr[5].id = SAI_SWITCH_ATTR_PACKET_EVENT_NOTIFY;
attr[5].value.ptr = reinterpret_cast<sai_pointer_t>(&on_packet_event);
sai_switch_api->create_switch(&gSwitchId, attrSz, attr);
2)stub版本的创建芯片
const sai_switch_api_t switch_api = {
stub_initialize_switch,
stub_shutdown_switch,
stub_connect_switch,
stub_disconnect_switch,
stub_set_switch_attribute,
stub_get_switch_attribute,
};
sai_status_t stub_initialize_switch(_In_ sai_switch_profile_id_t profile_id,
_In_reads_z_(SAI_MAX_HARDWARE_ID_LEN) char * switch_hardware_id,
_In_reads_opt_z_(SAI_MAX_FIRMWARE_PATH_NAME_LEN) char* firmware_path_name,
_In_ sai_switch_notification_t * switch_notifications)
memcpy(&g_notification_callbacks, switch_notifications, sizeof(g_notification_callbacks));
db_init_vlan();
db_init_next_hop_group();
3)创建rpc线程
start_sai_thrift_rpc_server(SWITCH_SAI_THRIFT_RPC_SERVER_PORT);
2、rpc线程
static void * switch_sai_thrift_rpc_server_thread(void *arg) {
int port = *(int *) arg;
shared_ptr<switch_sai_rpcHandler> handler(new switch_sai_rpcHandler());
shared_ptr<TProcessor> processor(new switch_sai_rpcProcessor(handler));
shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
server.serve();
return 0;
}
3、功能处理,以创建vlan为例 //class switch_sai_rpcHandler
1) sai_thrift_object_id_t sai_thrift_create_vlan(const std_sai_thrift_attr_vctr_t &thrift_attr_list)
sai_api_query(SAI_API_VLAN, reinterpret_cast<void**>(&vlan_api)); //获取vlan模块函数集
sai_thrift_parse_vlan_attributes(thrift_attr_list, attr_list);
vlan_api->create_vlan(&vlanObjId, gSwitchId, attr_size, attr_list); //创建vlan
2)sai_api_query
sai_status_t sai_api_query(_In_ sai_api_t sai_api_id, _Out_ void** api_method_table)
case SAI_API_VLAN:
*(const sai_vlan_api_t**)api_method_table = &vlan_api; //各芯片提供各个模块的函数集
return SAI_STATUS_SUCCESS;
case SAI_API_ROUTE:
*(const sai_route_api_t**)api_method_table = &route_api;
return SAI_STATUS_SUCCESS;
3)stub or sdk
const sai_vlan_api_t vlan_api = {
stub_create_vlan,
stub_remove_vlan,
stub_set_vlan_attribute,
stub_get_vlan_attribute,
stub_add_ports_to_vlan,
stub_remove_ports_from_vlan,
stub_remove_all_vlans,
stub_get_vlan_stats,
NULL
};
4、获取函数集,sai_api_query
switch (sai_api_id) {
case SAI_API_SWITCH:
*(const sai_switch_api_t**)api_method_table = &switch_api;
return SAI_STATUS_SUCCESS;
case SAI_API_PORT:
*(const sai_port_api_t**)api_method_table = &port_api;
return SAI_STATUS_SUCCESS;
case SAI_API_FDB:
*(const sai_fdb_api_t**)api_method_table = &fdb_api;
return SAI_STATUS_SUCCESS;
case SAI_API_VLAN:
*(const sai_vlan_api_t**)api_method_table = &vlan_api;
return SAI_STATUS_SUCCESS;
case SAI_API_VIRTUAL_ROUTER:
*(const sai_virtual_router_api_t**)api_method_table = &router_api;
return SAI_STATUS_SUCCESS;
case SAI_API_ROUTE:
*(const sai_route_api_t**)api_method_table = &route_api;
return SAI_STATUS_SUCCESS;
case SAI_API_NEXT_HOP:
*(const sai_next_hop_api_t**)api_method_table = &next_hop_api;
return SAI_STATUS_SUCCESS;
case SAI_API_NEXT_HOP_GROUP:
*(const sai_next_hop_group_api_t**)api_method_table = &next_hop_group_api;
return SAI_STATUS_SUCCESS;
case SAI_API_ROUTER_INTERFACE:
*(const sai_router_interface_api_t**)api_method_table = &router_interface_api;
return SAI_STATUS_SUCCESS;
case SAI_API_NEIGHBOR:
*(const sai_neighbor_api_t**)api_method_table = &neighbor_api;
return SAI_STATUS_SUCCESS;
case SAI_API_QOS_MAPS:
/* TODO : implement */
return SAI_STATUS_NOT_IMPLEMENTED;
case SAI_API_ACL:
/* TODO : implement */
return SAI_STATUS_NOT_IMPLEMENTED;
case SAI_API_HOST_INTERFACE:
*(const sai_hostif_api_t**)api_method_table = &host_interface_api;
return SAI_STATUS_SUCCESS;
模块划分:
typedef enum _sai_api_t
{
SAI_API_UNSPECIFIED = 0, /**< unspecified API */
SAI_API_SWITCH = 1, /**< sai_switch_api_t */
SAI_API_PORT = 2, /**< sai_port_api_t */
SAI_API_FDB = 3, /**< sai_fdb_api_t */
SAI_API_VLAN = 4, /**< sai_vlan_api_t */
SAI_API_VIRTUAL_ROUTER = 5, /**< sai_virtual_router_api_t */
SAI_API_ROUTE = 6, /**< sai_route_api_t */
SAI_API_NEXT_HOP = 7, /**< sai_next_hop_api_t */
SAI_API_NEXT_HOP_GROUP = 8, /**< sai_next_hop_group_api_t */
SAI_API_ROUTER_INTERFACE = 9, /**< sai_router_interface_api_t */
SAI_API_NEIGHBOR = 10, /**< sai_neighbor_api_t */
SAI_API_ACL = 11, /**< sai_acl_api_t */
SAI_API_HOSTIF = 12, /**< sai_hostif_api_t */
SAI_API_MIRROR = 13, /**< sai_mirror_api_t */
SAI_API_SAMPLEPACKET = 14, /**< sai_samplepacket_api_t */
SAI_API_STP = 15, /**< sai_stp_api_t */
SAI_API_LAG = 16, /**< sai_lag_api_t */
SAI_API_POLICER = 17, /**< sai_policer_api_t */
SAI_API_WRED = 18, /**< sai_wred_api_t */
SAI_API_QOS_MAP = 19, /**< sai_qos_map_api_t */
SAI_API_QUEUE = 20, /**< sai_queue_api_t */
SAI_API_SCHEDULER = 21, /**< sai_scheduler_api_t */
SAI_API_SCHEDULER_GROUP = 22, /**< sai_scheduler_group_api_t */
SAI_API_BUFFER = 23, /**< sai_buffer_api_t */
SAI_API_HASH = 24, /**< sai_hash_api_t */
SAI_API_UDF = 25, /**< sai_udf_api_t */
SAI_API_TUNNEL = 26, /**< sai_tunnel_api_t */
SAI_API_L2MC = 27, /**< sai_l2mc_api_t */
SAI_API_IPMC = 28, /**< sai_ipmc_api_t */
SAI_API_RPF_GROUP = 29, /**< sai_rpf_group_api_t */
SAI_API_L2MC_GROUP = 30, /**< sai_l2mc_group_api_t */
SAI_API_IPMC_GROUP = 31, /**< sai_ipmc_group_api_t */
SAI_API_MCAST_FDB = 32, /**< sai_mcast_fdb_api_t */
SAI_API_BRIDGE = 33, /**< sai_bridge_api_t */
SAI_API_TAM = 34, /**< sai_tam_api_t */
SAI_API_SEGMENTROUTE = 35, /**< sai_segmentroute_api_t */
SAI_API_MPLS = 36, /**< sai_mpls_api_t */
SAI_API_UBURST = 37, /**< sai_uburst_api_t */
SAI_API_MAX = 38, /**< total number of APIs */
} sai_api_t;