該部分經過redis的鍵空間機制訂閱鍵config_db的鍵事件,將其同步到內核,本進程存在swss docker中。linux
相關文件:c++
intfmgrd.cppredis
intfmgrd.hdocker
intfmgr.cpp數據庫
class IntfMgr : public Orch { public: IntfMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, const vector<string> &tableNames); using Orch::doTask; private: ProducerStateTable m_appIntfTableProducer;//做爲appdb的生產者 Table m_cfgIntfTable, m_cfgVlanIntfTable; Table m_statePortTable, m_stateLagTable, m_stateVlanTable; bool setIntfIp(const string &alias, const string &opCmd, const string &ipPrefixStr); void doTask(Consumer &consumer); bool isIntfStateOk(const string &alias); }; }
//該進程的功能是根據配置文件中的接口地址信息配置linux內核。 //使用以下命令進行配置: //ip address add 10.254.229.226/27 dev Ethernet20 //不支持在加載配置後使用ip address add 命令修改地址,想要修改數據口地址須要更改config_db //後從新reload配置。 //本進程的目標是將配置文件的關於接口IP的信息同步到內核。 int main(int argc, char **argv) { Logger::linkToDbNative("intfmgrd"); SWSS_LOG_ENTER(); SWSS_LOG_NOTICE("--- Starting intfmgrd ---"); try { //訂閱了db4中的三個表格 vector<string> cfg_intf_tables = { CFG_INTF_TABLE_NAME, CFG_LAG_INTF_TABLE_NAME, CFG_VLAN_INTF_TABLE_NAME, }; //鏈接CONFIG_DB,APPL_DB,STATE_DB,用於讀取信息 DBConnector cfgDb(CONFIG_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); DBConnector appDb(APPL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); DBConnector stateDb(STATE_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); IntfMgr intfmgr(&cfgDb, &appDb, &stateDb, cfg_intf_tables); // TODO: add tables in stateDB which interface depends on to monitor list std::vector<Orch *> cfgOrchList = {&intfmgr}; swss::Select s; for (Orch *o : cfgOrchList)//運行epoll,監聽數據庫信息 { s.addSelectables(o->getSelectables()); } SWSS_LOG_NOTICE("starting main loop"); while (true) { Selectable *sel; int ret; //一秒超時,即便訂閱的三個數據庫沒有事件發生也要週期性的處理事件,相似於實現了一個1秒定時器 ret = s.select(&sel, SELECT_TIMEOUT); if (ret == Select::ERROR) { SWSS_LOG_NOTICE("Error: %s!", strerror(errno)); continue; } //超時依然須要運行該函數 if (ret == Select::TIMEOUT) { intfmgr.doTask(); continue; } auto *c = (Executor *)sel; c->execute();//執行do-task } } catch(const std::exception &e) { SWSS_LOG_ERROR("Runtime error: %s", e.what()); } return -1; } #define VLAN_PREFIX "Vlan" #define LAG_PREFIX "PortChannel" IntfMgr::IntfMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, const vector<string> &tableNames) : Orch(cfgDb, tableNames), m_cfgIntfTable(cfgDb, CFG_INTF_TABLE_NAME), m_cfgVlanIntfTable(cfgDb, CFG_VLAN_INTF_TABLE_NAME), m_statePortTable(stateDb, STATE_PORT_TABLE_NAME),//讀取port狀態信息 m_stateLagTable(stateDb, STATE_LAG_TABLE_NAME),//讀取lag狀態信息 m_stateVlanTable(stateDb, STATE_VLAN_TABLE_NAME),//讀取vlan狀態信息 m_appIntfTableProducer(appDb, APP_INTF_TABLE_NAME)//做爲appdb的生產者,將配置文件的接口配置信息寫入APP_INTF_TABLE_NAME表 { } //調用ip address add 10.254.229.226/27 dev Ethernet20命令設置接口IP bool IntfMgr::setIntfIp(const string &alias, const string &opCmd, const string &ipPrefixStr) { stringstream cmd; string res; cmd << IP_CMD << " address " << opCmd << " " << ipPrefixStr << " dev " << alias;; int ret = swss::exec(cmd.str(), res); return (ret == 0); } //從db 6中獲取端口狀態信息 bool IntfMgr::isIntfStateOk(const string &alias) { vector<FieldValueTuple> temp; if (!alias.compare(0, strlen(VLAN_PREFIX), VLAN_PREFIX))//vlan接口 { if (m_stateVlanTable.get(alias, temp)) { SWSS_LOG_DEBUG("Vlan %s is ready", alias.c_str()); return true; } } else if (!alias.compare(0, strlen(LAG_PREFIX), LAG_PREFIX))//lag接口 { if (m_stateLagTable.get(alias, temp)) { SWSS_LOG_DEBUG("Lag %s is ready", alias.c_str()); return true; } } else if (m_statePortTable.get(alias, temp))//port接口 { SWSS_LOG_DEBUG("Port %s is ready", alias.c_str()); return true; } return false; } //"INTERFACE|Ethernet20|10.254.229.226/27" //"PORTCHANNEL_INTERFACE|PortChannel1|10.8.8.200/24" //該程序會處理INTERFACE,PORTCHANNEL_INTERFACE,VLAN_INTERFACE三類接口信息 //配置了IP,interface表示一個三層的概念,包括子接口,vlanif,lag-if,phy-if void IntfMgr::doTask(Consumer &consumer) { SWSS_LOG_ENTER(); auto it = consumer.m_toSync.begin(); while (it != consumer.m_toSync.end()) { KeyOpFieldsValuesTuple t = it->second; string keySeparator = CONFIGDB_KEY_SEPARATOR; vector<string> keys = tokenize(kfvKey(t), keySeparator[0]); string alias(keys[0]);//keys[0]爲INTERFACE //不是vlan接口的ip地址到此結束,其它類型的接口lag,ethernrt都由interface_config.service進行配置 if (alias.compare(0, strlen(VLAN_PREFIX), VLAN_PREFIX)) { /* handle IP over vlan Only for now, skip the rest */ it = consumer.m_toSync.erase(it); continue; } size_t pos = kfvKey(t).find(CONFIGDB_KEY_SEPARATOR); if (pos == string::npos) { SWSS_LOG_DEBUG("Invalid key %s", kfvKey(t).c_str()); it = consumer.m_toSync.erase(it); continue; } //提取key中的10.254.229.226/27部分 IpPrefix ip_prefix(kfvKey(t).substr(pos+1)); SWSS_LOG_DEBUG("intfs doTask: %s", (dumpTuple(consumer, t)).c_str()); string op = kfvOp(t); if (op == SET_COMMAND) { /* * Don't proceed if port/lag/VLAN is not ready yet. * The pending task will be checked periodially and retried. * TODO: Subscribe to stateDB for port/lag/VLAN state and retry * pending tasks immediately upon state change. * 由定時器超時1秒觸發一次,只有沒有up的端口將會由定時器持續檢查。 */ if (!isIntfStateOk(alias))//判斷端口是否已經ok { SWSS_LOG_DEBUG("Interface is not ready, skipping %s", kfvKey(t).c_str()); it++; continue; } string opCmd("add"); string ipPrefixStr = ip_prefix.to_string(); //設置接口IP地址 setIntfIp(alias, opCmd, ipPrefixStr); } else if (op == DEL_COMMAND) { string opCmd("del"); string ipPrefixStr = ip_prefix.to_string(); setIntfIp(alias, opCmd, ipPrefixStr); } it = consumer.m_toSync.erase(it); continue; } }
前面分析過sonic對netlink的相關處理,此處再也不贅述。json
該部分的主要文件有:api
intfsync.cppapp
intfsync.hasync
intfsyncd.cpp函數
class IntfSync : public NetMsg { public: enum { MAX_ADDR_SIZE = 64 }; IntfSync(DBConnector *db);//鏈接數據庫APP_DB virtual void onMsg(int nlmsg_type, struct nl_object *obj); private: ProducerStateTable m_intfTable;//app_db的INTF_TABLE表生產者實例 }; } //消息處理函數 void IntfSync::onMsg(int nlmsg_type, struct nl_object *obj) { char addrStr[MAX_ADDR_SIZE + 1] = {0}; struct rtnl_addr *addr = (struct rtnl_addr *)obj; string key; string scope = "global"; string family; //響應新地址,獲取地址,刪除地址三個信息 if ((nlmsg_type != RTM_NEWADDR) && (nlmsg_type != RTM_GETADDR) && (nlmsg_type != RTM_DELADDR)) return; /* Don't sync local routes,不一樣步local地址信息 */ if (rtnl_addr_get_scope(addr) != RT_SCOPE_UNIVERSE) { scope = "local"; return; } if (rtnl_addr_get_family(addr) == AF_INET) family = IPV4_NAME; else if (rtnl_addr_get_family(addr) == AF_INET6) family = IPV6_NAME; else // Not supported return; //獲取接口名字以及地址,組合成key key = LinkCache::getInstance().ifindexToName(rtnl_addr_get_ifindex(addr)); key+= ":"; nl_addr2str(rtnl_addr_get_local(addr), addrStr, MAX_ADDR_SIZE); key+= addrStr; if (nlmsg_type == RTM_DELADDR)//地址刪除,刪除key { m_intfTable.del(key); return; } //添加key std::vector<FieldValueTuple> fvVector; FieldValueTuple f("family", family); FieldValueTuple s("scope", scope); fvVector.push_back(s); fvVector.push_back(f); m_intfTable.set(key, fvVector); }
//進程運行在容器swss中 int main(int argc, char **argv) { swss::Logger::linkToDbNative("intfsyncd"); DBConnector db(APPL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0);//鏈接APPL_DB IntfSync sync(&db);//實例化netmsg //訂閱消息,加入組播組 NetDispatcher::getInstance().registerMessageHandler(RTM_NEWADDR, &sync); NetDispatcher::getInstance().registerMessageHandler(RTM_DELADDR, &sync); while (1) { try { NetLink netlink; Select s; netlink.registerGroup(RTNLGRP_IPV4_IFADDR); netlink.registerGroup(RTNLGRP_IPV6_IFADDR); cout << "Listens to interface messages..." << endl; netlink.dumpRequest(RTM_GETADDR);//打印全部地址 s.addSelectable(&netlink);//加入select事件 while (true) { Selectable *temps; s.select(&temps);//監聽select事件 } } catch (const std::exception& e) { cout << "Exception \"" << e.what() << "\" had been thrown in deamon" << endl; return 0; } } return 1; }
127.0.0.1:6379> HGETALL "INTF_TABLE:PortChannel1:10.8.8.200/24" 1) "scope" 2) "global" 3) "family" 4) "IPv4" 127.0.0.1:6379>
該部分做爲app_db的一個訂閱者,訂閱INTF_TABLE變化。添加一個IP則在sonic層添加一個rif口,一個物理口只能添加一個IP。
主要相關文件:
intfsorch.cpp
intfsorch.h
該部分收到INTF_TABLE信息變化後會產生四部分信息:
該部分會將linux內核的local路由表同步到sonic中。
class IntfsOrch : public Orch { public: IntfsOrch(DBConnector *db, string tableName);//訂閱table sai_object_id_t getRouterIntfsId(const string&); std::set<IpPrefix> getRouterIntfsIpAddresses(const string&); void increaseRouterIntfsRefCount(const string&); void decreaseRouterIntfsRefCount(const string&); private: IntfsTable m_syncdIntfses; void doTask(Consumer &consumer); int getRouterIntfsRefCount(const string&); bool addRouterIntfs(Port &port); bool removeRouterIntfs(Port &port); //添加rif網段子網路由 void addSubnetRoute(const Port &port, const IpPrefix &ip_prefix); void removeSubnetRoute(const Port &port, const IpPrefix &ip_prefix); //添加本機路由 void addIp2MeRoute(const IpPrefix &ip_prefix); void removeIp2MeRoute(const IpPrefix &ip_prefix); //添加鄰居 void addDirectedBroadcast(const Port &port, const IpAddress &ip_addr); void removeDirectedBroadcast(const Port &port, const IpAddress &ip_addr); };
const int intfsorch_pri = 35; //構造函數,生成一個orch,訂閱表格APP_INTF_TABLE_NAME IntfsOrch::IntfsOrch(DBConnector *db, string tableName) : Orch(db, tableName, intfsorch_pri) { SWSS_LOG_ENTER(); } //根據接口名獲取port相關信息 sai_object_id_t IntfsOrch::getRouterIntfsId(const string &alias) { Port port; gPortsOrch->getPort(alias, port); assert(port.m_rif_id); return port.m_rif_id; } void IntfsOrch::increaseRouterIntfsRefCount(const string &alias) { SWSS_LOG_ENTER(); m_syncdIntfses[alias].ref_count++; SWSS_LOG_DEBUG("Router interface %s ref count is increased to %d", alias.c_str(), m_syncdIntfses[alias].ref_count); } void IntfsOrch::decreaseRouterIntfsRefCount(const string &alias) { SWSS_LOG_ENTER(); m_syncdIntfses[alias].ref_count--; SWSS_LOG_DEBUG("Router interface %s ref count is decreased to %d", alias.c_str(), m_syncdIntfses[alias].ref_count); } void IntfsOrch::doTask(Consumer &consumer) { SWSS_LOG_ENTER(); if (!gPortsOrch->isInitDone()) { return; } auto it = consumer.m_toSync.begin(); while (it != consumer.m_toSync.end()) { KeyOpFieldsValuesTuple t = it->second; vector<string> keys = tokenize(kfvKey(t), ':'); string alias(keys[0]); IpPrefix ip_prefix(kfvKey(t).substr(kfvKey(t).find(':')+1)); if (alias == "eth0" || alias == "docker0") { it = consumer.m_toSync.erase(it); continue; } string op = kfvOp(t); if (op == SET_COMMAND) { if (alias == "lo") { addIp2MeRoute(ip_prefix); it = consumer.m_toSync.erase(it); continue; } Port port; if (!gPortsOrch->getPort(alias, port)) { /* TODO: Resolve the dependency relationship and add ref_count to port */ it++; continue; } // buffer configuration hasn't been applied yet, hold from intf config. if (!gBufferOrch->isPortReady(alias)) { it++; continue; } auto it_intfs = m_syncdIntfses.find(alias); if (it_intfs == m_syncdIntfses.end()) { if (addRouterIntfs(port)) { IntfsEntry intfs_entry; intfs_entry.ref_count = 0; m_syncdIntfses[alias] = intfs_entry; } else { it++; continue; } } if (m_syncdIntfses[alias].ip_addresses.count(ip_prefix)) { /* Duplicate entry */ it = consumer.m_toSync.erase(it); continue; } /* NOTE: Overlap checking is required to handle ifconfig weird behavior. * When set IP address using ifconfig command it applies it in two stages. * On stage one it sets IP address with netmask /8. On stage two it * changes netmask to specified in command. As DB is async event to * add IP address with original netmask may come before event to * delete IP with netmask /8. To handle this we in case of overlap * we should wait until entry with /8 netmask will be removed. * Time frame between those event is quite small.*/ bool overlaps = false; for (const auto &prefixIt: m_syncdIntfses[alias].ip_addresses) { if (prefixIt.isAddressInSubnet(ip_prefix.getIp()) || ip_prefix.isAddressInSubnet(prefixIt.getIp())) { overlaps = true; SWSS_LOG_NOTICE("Router interface %s IP %s overlaps with %s.", port.m_alias.c_str(), prefixIt.to_string().c_str(), ip_prefix.to_string().c_str()); break; } } if (overlaps) { /* Overlap of IP address network */ ++it; continue; } addSubnetRoute(port, ip_prefix); addIp2MeRoute(ip_prefix); if(port.m_type == Port::VLAN && ip_prefix.isV4()) { addDirectedBroadcast(port, ip_prefix.getBroadcastIp()); } m_syncdIntfses[alias].ip_addresses.insert(ip_prefix); it = consumer.m_toSync.erase(it); } else if (op == DEL_COMMAND) { if (alias == "lo") { removeIp2MeRoute(ip_prefix); it = consumer.m_toSync.erase(it); continue; } Port port; /* Cannot locate interface */ if (!gPortsOrch->getPort(alias, port)) { it = consumer.m_toSync.erase(it); continue; } if (m_syncdIntfses.find(alias) != m_syncdIntfses.end()) { if (m_syncdIntfses[alias].ip_addresses.count(ip_prefix)) { removeSubnetRoute(port, ip_prefix); removeIp2MeRoute(ip_prefix); if(port.m_type == Port::VLAN && ip_prefix.isV4()) { removeDirectedBroadcast(port, ip_prefix.getBroadcastIp()); } m_syncdIntfses[alias].ip_addresses.erase(ip_prefix); } /* Remove router interface that no IP addresses are associated with */ if (m_syncdIntfses[alias].ip_addresses.size() == 0) { if (removeRouterIntfs(port)) { m_syncdIntfses.erase(alias); it = consumer.m_toSync.erase(it); } else it++; } else { it = consumer.m_toSync.erase(it); } } else /* Cannot locate the interface */ it = consumer.m_toSync.erase(it); } } } //添加路由接口rif bool IntfsOrch::addRouterIntfs(Port &port) { SWSS_LOG_ENTER(); /* Return true if the router interface exists */ if (port.m_rif_id) { SWSS_LOG_WARN("Router interface already exists on %s", port.m_alias.c_str()); return true; } /* Create router interface if the router interface doesn't exist */ sai_attribute_t attr; vector<sai_attribute_t> attrs; attr.id = SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID; attr.value.oid = gVirtualRouterId; attrs.push_back(attr); attr.id = SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS; memcpy(attr.value.mac, gMacAddress.getMac(), sizeof(sai_mac_t)); attrs.push_back(attr); attr.id = SAI_ROUTER_INTERFACE_ATTR_TYPE; switch(port.m_type) { case Port::PHY: case Port::LAG: attr.value.s32 = SAI_ROUTER_INTERFACE_TYPE_PORT; break; case Port::VLAN: attr.value.s32 = SAI_ROUTER_INTERFACE_TYPE_VLAN; break; default: SWSS_LOG_ERROR("Unsupported port type: %d", port.m_type); break; } attrs.push_back(attr); switch(port.m_type) { case Port::PHY: attr.id = SAI_ROUTER_INTERFACE_ATTR_PORT_ID; attr.value.oid = port.m_port_id; break; case Port::LAG: attr.id = SAI_ROUTER_INTERFACE_ATTR_PORT_ID; attr.value.oid = port.m_lag_id; break; case Port::VLAN: attr.id = SAI_ROUTER_INTERFACE_ATTR_VLAN_ID; attr.value.oid = port.m_vlan_info.vlan_oid; break; default: SWSS_LOG_ERROR("Unsupported port type: %d", port.m_type); break; } attrs.push_back(attr); attr.id = SAI_ROUTER_INTERFACE_ATTR_MTU; attr.value.u32 = port.m_mtu; attrs.push_back(attr); try { gCrmOrch->preCrmResCounter(CrmResourceType::CRM_SUBNET_TABLE); sai_status_t status = sai_router_intfs_api->create_router_interface(&port.m_rif_id, gSwitchId, (uint32_t)attrs.size(), attrs.data()); if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to create router interface for port %s, rv:%d", port.m_alias.c_str(), status); throw runtime_error("Failed to create router interface."); } gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_SUBNET_TABLE); } catch (...) { SWSS_LOG_ERROR("Failed to create router interface for port %s", port.m_alias.c_str()); return false; } gPortsOrch->setPort(port.m_alias, port); SWSS_LOG_NOTICE("Create router interface for port %s mtu %u", port.m_alias.c_str(), port.m_mtu); return true; } bool IntfsOrch::removeRouterIntfs(Port &port) { SWSS_LOG_ENTER(); if (m_syncdIntfses[port.m_alias].ref_count > 0) { SWSS_LOG_NOTICE("Router interface is still referenced"); return false; } try { sai_status_t status = sai_router_intfs_api->remove_router_interface(port.m_rif_id); if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to remove router interface for port %s, rv:%d", port.m_alias.c_str(), status); throw runtime_error("Failed to remove router interface."); } gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_SUBNET_TABLE); } catch (...) { SWSS_LOG_ERROR("Failed to remove router interface for port %s", port.m_alias.c_str()); return false; } port.m_rif_id = 0; gPortsOrch->setPort(port.m_alias, port); SWSS_LOG_NOTICE("Remove router interface for port %s", port.m_alias.c_str()); return true; } //添加子網路由 void IntfsOrch::addSubnetRoute(const Port &port, const IpPrefix &ip_prefix) { sai_route_entry_t unicast_route_entry; unicast_route_entry.switch_id = gSwitchId; unicast_route_entry.vr_id = gVirtualRouterId; unicast_route_entry.table_id = SAI_NULL_OBJECT_ID; copy(unicast_route_entry.destination, ip_prefix); subnet(unicast_route_entry.destination, unicast_route_entry.destination); sai_attribute_t attr; vector<sai_attribute_t> attrs; attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; attr.value.s32 = SAI_PACKET_ACTION_FORWARD; attrs.push_back(attr); //指向出接口爲本rif attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; attr.value.oid = port.m_rif_id; attrs.push_back(attr); sai_status_t status = sai_route_api->create_route_entry(&unicast_route_entry, (uint32_t)attrs.size(), attrs.data()); if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to create subnet route to %s from %s, rv:%d", ip_prefix.to_string().c_str(), port.m_alias.c_str(), status); throw runtime_error("Failed to create subnet route."); } SWSS_LOG_NOTICE("Create subnet route to %s from %s", ip_prefix.to_string().c_str(), port.m_alias.c_str()); increaseRouterIntfsRefCount(port.m_alias); gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_UNDERLAY_LPM_ROUTE); if (unicast_route_entry.destination.addr_family == SAI_IP_ADDR_FAMILY_IPV4) { gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_IPV4_ROUTE); } else { gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_IPV6_ROUTE); } } //刪除子網路由 void IntfsOrch::removeSubnetRoute(const Port &port, const IpPrefix &ip_prefix) { sai_route_entry_t unicast_route_entry; unicast_route_entry.switch_id = gSwitchId; unicast_route_entry.vr_id = gVirtualRouterId; unicast_route_entry.table_id = SAI_NULL_OBJECT_ID; copy(unicast_route_entry.destination, ip_prefix); subnet(unicast_route_entry.destination, unicast_route_entry.destination); sai_status_t status = sai_route_api->remove_route_entry(&unicast_route_entry); if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to remove subnet route to %s from %s, rv:%d", ip_prefix.to_string().c_str(), port.m_alias.c_str(), status); throw runtime_error("Failed to remove subnet route."); } SWSS_LOG_NOTICE("Remove subnet route to %s from %s", ip_prefix.to_string().c_str(), port.m_alias.c_str()); decreaseRouterIntfsRefCount(port.m_alias); gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_UNDERLAY_LPM_ROUTE); if (unicast_route_entry.destination.addr_family == SAI_IP_ADDR_FAMILY_IPV4) { gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_IPV4_ROUTE); } else { gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_IPV6_ROUTE); } } //添加上送本機的路由,32位本機路由 void IntfsOrch::addIp2MeRoute(const IpPrefix &ip_prefix) { sai_route_entry_t unicast_route_entry; unicast_route_entry.switch_id = gSwitchId; unicast_route_entry.vr_id = gVirtualRouterId; unicast_route_entry.table_id = SAI_NULL_OBJECT_ID; copy(unicast_route_entry.destination, ip_prefix.getIp()); sai_attribute_t attr; vector<sai_attribute_t> attrs; attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; attr.value.s32 = SAI_PACKET_ACTION_FORWARD; attrs.push_back(attr); Port cpu_port; gPortsOrch->getCpuPort(cpu_port); //指向出接口爲cpu的物理接口 attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; attr.value.oid = cpu_port.m_port_id; attrs.push_back(attr); sai_status_t status = sai_route_api->create_route_entry(&unicast_route_entry, (uint32_t)attrs.size(), attrs.data()); if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to create IP2me route ip:%s, rv:%d", ip_prefix.getIp().to_string().c_str(), status); throw runtime_error("Failed to create IP2me route."); } SWSS_LOG_NOTICE("Create IP2me route ip:%s", ip_prefix.getIp().to_string().c_str()); gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_UNDERLAY_HOST_ROUTE); if (unicast_route_entry.destination.addr_family == SAI_IP_ADDR_FAMILY_IPV4) { gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_IPV4_ROUTE); } else { gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_IPV6_ROUTE); } } //刪除上送本機的路由 void IntfsOrch::removeIp2MeRoute(const IpPrefix &ip_prefix) { sai_route_entry_t unicast_route_entry; unicast_route_entry.switch_id = gSwitchId; unicast_route_entry.vr_id = gVirtualRouterId; unicast_route_entry.table_id = SAI_NULL_OBJECT_ID; copy(unicast_route_entry.destination, ip_prefix.getIp()); sai_status_t status = sai_route_api->remove_route_entry(&unicast_route_entry); if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to remove IP2me route ip:%s, rv:%d", ip_prefix.getIp().to_string().c_str(), status); throw runtime_error("Failed to remove IP2me route."); } SWSS_LOG_NOTICE("Remove packet action trap route ip:%s", ip_prefix.getIp().to_string().c_str()); gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_UNDERLAY_HOST_ROUTE); if (unicast_route_entry.destination.addr_family == SAI_IP_ADDR_FAMILY_IPV4) { gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_IPV4_ROUTE); } else { gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_IPV6_ROUTE); } } //設置本rif口的鄰居爲廣播 void IntfsOrch::addDirectedBroadcast(const Port &port, const IpAddress &ip_addr) { sai_status_t status; sai_neighbor_entry_t neighbor_entry; neighbor_entry.rif_id = port.m_rif_id; neighbor_entry.switch_id = gSwitchId; copy(neighbor_entry.ip_address, ip_addr); sai_attribute_t neighbor_attr; neighbor_attr.id = SAI_NEIGHBOR_ENTRY_ATTR_DST_MAC_ADDRESS; memcpy(neighbor_attr.value.mac, MacAddress("ff:ff:ff:ff:ff:ff").getMac(), 6); status = sai_neighbor_api->create_neighbor_entry(&neighbor_entry, 1, &neighbor_attr); if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to create broadcast entry %s rv:%d", ip_addr.to_string().c_str(), status); return; } SWSS_LOG_NOTICE("Add broadcast route for ip:%s", ip_addr.to_string().c_str()); } void IntfsOrch::removeDirectedBroadcast(const Port &port, const IpAddress &ip_addr) { sai_status_t status; sai_neighbor_entry_t neighbor_entry; neighbor_entry.rif_id = port.m_rif_id; neighbor_entry.switch_id = gSwitchId; copy(neighbor_entry.ip_address, ip_addr); status = sai_neighbor_api->remove_neighbor_entry(&neighbor_entry); if (status != SAI_STATUS_SUCCESS) { if (status == SAI_STATUS_ITEM_NOT_FOUND) { SWSS_LOG_ERROR("No broadcast entry found for %s", ip_addr.to_string().c_str()); } else { SWSS_LOG_ERROR("Failed to remove broadcast entry %s rv:%d", ip_addr.to_string().c_str(), status); } return; } SWSS_LOG_NOTICE("Remove broadcast route ip:%s", ip_addr.to_string().c_str()); } std::set<IpPrefix> IntfsOrch::getRouterIntfsIpAddresses(const string& alias) { auto iter = m_syncdIntfses.find(alias); if (iter == m_syncdIntfses.end()) return set<IpPrefix>(); return iter->second.ip_addresses; }
該orch不以單獨進程出現,它是orchagent進程的一個子orch。
127.0.0.1:6379[1]> KEYS *ROUTER* 1) "ASIC_STATE:SAI_OBJECT_TYPE_VIRTUAL_ROUTER:oid:0x3000000000084" 2) "ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x60000000005d3" 127.0.0.1:6379[1]> HGETALL "ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x60000000005d3" 1) "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID" 2) "oid:0x3000000000084" 3) "SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS" 4) "00:90:FB:60:E2:86" 5) "SAI_ROUTER_INTERFACE_ATTR_TYPE" 6) "SAI_ROUTER_INTERFACE_TYPE_PORT" 7) "SAI_ROUTER_INTERFACE_ATTR_PORT_ID" 8) "oid:0x20000000005d2" 9) "SAI_ROUTER_INTERFACE_ATTR_MTU" 10) "9100" 127.0.0.1:6379[1]> 127.0.0.1:6379[1]> KEYS *ROUTE* 1) "ASIC_STATE:SAI_OBJECT_TYPE_VIRTUAL_ROUTER:oid:0x3000000000084" 2) "ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"10.8.8.200/32\",\"switch_id\":\"oid:0x21000000000000\",\"vr\":\"oid:0x3000000000084\"}" 3) "ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"10.1.0.32/32\",\"switch_id\":\"oid:0x21000000000000\",\"vr\":\"oid:0x3000000000084\"}" 4) "ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x60000000005d3" 127.0.0.1:6379[1]> 127.0.0.1:6379[1]> KEYS *NEIG* 1) "ASIC_STATE:SAI_OBJECT_TYPE_NEIGHBOR_ENTRY:{\"ip\":\"10.8.8.87\",\"rif\":\"oid:0x60000000005d3\",\"switch_id\":\"oid:0x21000000000000\"}" 127.0.0.1:6379[1]>
syncd響應asic-db中的信息變化,將配置同步到硬件。