SONIC VLAN配置流程sonic vlan配置通过订阅config_db的键空间事件完成vlan配置信息从config_db到内核和硬件。config_db.json格式如下:
"VLAN": { "Vlan1000": { "vlanid": "1000" } }, "VLAN_MEMBER": { "Vlan1000|Ethernet16": { "tagging_mode": "untagged" } }, "VLAN_INTERFACE": { "Vlan1000|192.168.0.1/27": {} }, 在swss容器中存在一个vlanmgrd进行用于订阅config_db的vlan键空间,响应vlan配置,解析后将其同步到内核和app_db。由portsorch订阅app_db vlan事件,将其同步到asic-db,最终将其同步到硬件。VLAN_INTERFACE接口信息由intfmgr和intforch进行处理。
vlanmgr该进程运行在swss容器中,用于订阅config_db的vlan键空间,响应vlan配置,解析后将其同步到内核和app_db。
该部分涉及文件:
vlanmgrd.cpp
vlanmgr.cpp
vlanmgr.h
class VlanMgr : public Orch{public: VlanMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, const vector<string> &tableNames); using Orch::doTask;private: ProducerStateTable m_appVlanTableProducer, m_appVlanMemberTableProducer; Table m_cfgVlanTable, m_cfgVlanMemberTable; Table m_statePortTable, m_stateLagTable; Table m_stateVlanTable; std::set<std::string> m_vlans; void doTask(Consumer &consumer);//主任务 void doVlanTask(Consumer &consumer);//处理vlan事件 void doVlanMemberTask(Consumer &consumer);//处理vlan成员事件 void processUntaggedVlanMembers(string vlan, const string &members);//处理vlan内untag成员,暂时没用 bool addHostVlan(int vlan_id);//将vlan同步到host,即创建vlan bool removeHostVlan(int vlan_id);//删除host中的vlan bool setHostVlanAdminState(int vlan_id, const string &admin_status);//设置hostvlan状态 bool setHostVlanMtu(int vlan_id, uint32_t mtu);//设置host vlan接口的mtu //添加成员 bool addHostVlanMember(int vlan_id, const string &port_alias, const string& tagging_mode); bool removeHostVlanMember(int vlan_id, const string &port_alias);//删除host vlan成员 bool isMemberStateOk(const string &alias);//从state db中获取成员端口是否ok bool isVlanStateOk(const string &alias);//从state db中获取vlan是否ok bool isVlanMacOk();//判断该vlan的mac地址是否ok};实现int main(int argc, char **argv){ Logger::linkToDbNative("vlanmgrd"); SWSS_LOG_ENTER(); SWSS_LOG_NOTICE("--- Starting vlanmgrd ---"); try { vector<string> cfg_vlan_tables = {//订阅了两个config db table CFG_VLAN_TABLE_NAME, CFG_VLAN_MEMBER_TABLE_NAME, }; //连接了三个数据库 DBConnector cfgDb(CONFIG_DB, DBConnector::DEFAULT_UNIXSOCKET, 0);//读和订阅config-db数据 DBConnector appDb(APPL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0);//将配置希尔app-db DBConnector stateDb(STATE_DB, DBConnector::DEFAULT_UNIXSOCKET, 0);//获取vlan端口是否准备好 /* * swss service starts after interfaces-config.service which will have * switch_mac set. * Dynamic switch_mac update is not supported for now. * 获取全局的mac地址作为vlan-if的mac地址 */ Table table(&cfgDb, "DEVICE_METADATA"); std::vector<FieldValueTuple> ovalues; table.get("localhost", ovalues); auto it = std::find_if( ovalues.begin(), ovalues.end(), [](const FieldValueTuple& t){ return t.first == "mac";} ); if ( it == ovalues.end() ) { throw runtime_error("couldn't find MAC address of the device from config DB"); } gMacAddress = MacAddress(it->second); //构造vlanmgr VlanMgr vlanmgr(&cfgDb, &appDb, &stateDb, cfg_vlan_tables); std::vector<Orch *> cfgOrchList = {&vlanmgr}; swss::Select s; for (Orch *o : cfgOrchList) { s.addSelectables(o->getSelectables()); } SWSS_LOG_NOTICE("starting main loop"); while (true) { Selectable *sel; int ret; ret = s.select(&sel, SELECT_TIMEOUT); if (ret == Select::ERROR) { SWSS_LOG_NOTICE("Error: %s!", strerror(errno)); continue; } if (ret == Select::TIMEOUT) { vlanmgr.doTask(); continue; } auto *c = (Executor *)sel; c->execute(); } } catch(const std::exception &e) { SWSS_LOG_ERROR("Runtime error: %s", e.what()); } return -1;}VlanMgr::doTask(Consumer &consumer)//vlanmgr主任务,vlan没有sync进程监听内核的netlink事件,内核与硬件的vlan事件都//由vlanmgr负责,vlanmgr负责在linux内核创建vlan和vlan-member,同时往app-db中写入//vlan事件。同时vlanif的IP地址在intfmgr中进行添加,并同步到内核void VlanMgr::doTask(Consumer &consumer){ SWSS_LOG_ENTER(); //获取事件表格名 string table_name = consumer.getTableName(); if (table_name == CFG_VLAN_TABLE_NAME) { doVlanTask(consumer);//vlan添加创建 } else if (table_name == CFG_VLAN_MEMBER_TABLE_NAME) { doVlanMemberTask(consumer);//vlan成员添加创建 } else { SWSS_LOG_ERROR("Unknown config table %s ", table_name.c_str()); throw runtime_error("VlanMgr doTask failure."); }}VlanMgr::doVlanTask(Consumer &consumer)//执行vlan事件void VlanMgr::doVlanTask(Consumer &consumer){ if (!isVlanMacOk())//vlanmac是否准备好了,没有的话等待,这里就是个判断,vlanmac在vlanmgr起来时已经获取了 { SWSS_LOG_DEBUG("VLAN mac not ready, delaying VLAN task"); return; } auto it = consumer.m_toSync.begin(); while (it != consumer.m_toSync.end()) { auto &t = it->second; string key = kfvKey(t); /* Ensure the key starts with "Vlan" otherwise ignore */ if (strncmp(key.c_str(), VLAN_PREFIX, 4)) { SWSS_LOG_ERROR("Invalid key format. No 'Vlan' prefix: %s", key.c_str()); it = consumer.m_toSync.erase(it); continue; } int vlan_id; vlan_id = stoi(key.substr(4)); string vlan_alias, port_alias; string op = kfvOp(t); if (op == SET_COMMAND) { string admin_status; uint32_t mtu = 0; vector<FieldValueTuple> fvVector; string members; /* Add host VLAN when it has not been created. */ //添加vlan if (m_vlans.find(key) == m_vlans.end()) { addHostVlan(vlan_id); } /* set up host env .... */ //设置host vlan相关信息 for (auto i : kfvFieldsValues(t)) { /* Set vlan admin status 设置管理状态*/ if (fvField(i) == "admin_status") { admin_status = fvValue(i); setHostVlanAdminState(vlan_id, admin_status); fvVector.push_back(i); } /* Set vlan mtu 设置mtu */ else if (fvField(i) == "mtu") { mtu = (uint32_t)stoul(fvValue(i)); /* * TODO: support host VLAN mtu setting. * Host VLAN mtu should be set only after member configured * and VLAN state is not UNKNOWN. */ SWSS_LOG_DEBUG("%s mtu %u: Host VLAN mtu setting to be supported.", key.c_str(), mtu); fvVector.push_back(i); } else if (fvField(i) == "members@") { members = fvValue(i); } } /* fvVector should not be empty */ if (fvVector.empty()) { FieldValueTuple a("admin_status", "up"); fvVector.push_back(a); } //写入app-db m_appVlanTableProducer.set(key, fvVector); m_vlans.insert(key); //写入state-db(6) fvVector.clear(); FieldValueTuple s("state", "ok"); fvVector.push_back(s); m_stateVlanTable.set(key, fvVector); it = consumer.m_toSync.erase(it); /* * Members configured together with VLAN in untagged mode. * This is to be compatible with access VLAN configuration from minigraph. * untag模式配置vlan时,会跟随着vlan一起下发,所以在这里解决vlan成员添加问题。 * tag vlan则在单独的mem表中添加。 */ if (!members.empty()) { processUntaggedVlanMembers(key, members); } } else if (op == DEL_COMMAND)//删除 { if (m_vlans.find(key) != m_vlans.end()) { removeHostVlan(vlan_id);//找到删除 m_vlans.erase(key); m_appVlanTableProducer.del(key);//通知app-db m_stateVlanTable.del(key);//删除状态 } else { SWSS_LOG_ERROR("%s doesn't exist", key.c_str()); } SWSS_LOG_DEBUG("%s", (dumpTuple(consumer, t)).c_str()); it = consumer.m_toSync.erase(it); } else { SWSS_LOG_ERROR("Unknown operation type %s", op.c_str()); SWSS_LOG_DEBUG("%s", (dumpTuple(consumer, t)).c_str()); it = consumer.m_toSync.erase(it); } }}void VlanMgr::doVlanMemberTask(Consumer &consumer)//处理vlan-member事件void VlanMgr::doVlanMemberTask(Consumer &consumer){ auto it = consumer.m_toSync.begin(); while (it != consumer.m_toSync.end()) { auto &t = it->second; string key = kfvKey(t); /* Ensure the key starts with "Vlan" otherwise ignore */ if (strncmp(key.c_str(), VLAN_PREFIX, 4)) { SWSS_LOG_ERROR("Invalid key format. No 'Vlan' prefix: %s", key.c_str()); it = consumer.m_toSync.erase(it); continue; } key = key.substr(4); size_t found = key.find(CONFIGDB_KEY_SEPARATOR); int vlan_id; string vlan_alias, port_alias; if (found != string::npos) { vlan_id = stoi(key.substr(0, found)); port_alias = key.substr(found+1); } else { SWSS_LOG_ERROR("Invalid key format. No member port is presented: %s", kfvKey(t).c_str()); it = consumer.m_toSync.erase(it); continue; } //获取vlan名字 vlan_alias = VLAN_PREFIX + to_string(vlan_id); string op = kfvOp(t); // TODO: store port/lag/VLAN data in local data structure and perform more validations. if (op == SET_COMMAND) { /* Don't proceed if member port/lag is not ready yet */ if (!isMemberStateOk(port_alias) || !isVlanStateOk(vlan_alias)) { SWSS_LOG_DEBUG("%s not ready, delaying", kfvKey(t).c_str()); it++; continue; } string tagging_mode = "untagged"; for (auto i : kfvFieldsValues(t)) { if (fvField(i) == "tagging_mode") { tagging_mode = fvValue(i); } } if (tagging_mode != "untagged" && tagging_mode != "tagged" && tagging_mode != "priority_tagged") { SWSS_LOG_ERROR("Wrong tagging_mode '%s' for key: %s", tagging_mode.c_str(), kfvKey(t).c_str()); it = consumer.m_toSync.erase(it); continue; } //添加vlan成员 if (addHostVlanMember(vlan_id, port_alias, tagging_mode)) { key = VLAN_PREFIX + to_string(vlan_id); key += DEFAULT_KEY_SEPARATOR; key += port_alias;//写入app-db数据库 m_appVlanMemberTableProducer.set(key, kfvFieldsValues(t)); } it = consumer.m_toSync.erase(it); } else if (op == DEL_COMMAND) { removeHostVlanMember(vlan_id, port_alias); key = VLAN_PREFIX + to_string(vlan_id); key += DEFAULT_KEY_SEPARATOR; key += port_alias; m_appVlanMemberTableProducer.del(key); SWSS_LOG_DEBUG("%s", (dumpTuple(consumer, t)).c_str()); it = consumer.m_toSync.erase(it); } else { SWSS_LOG_ERROR("Unknown operation type %s", op.c_str()); it = consumer.m_toSync.erase(it); } }}同步app_db数据到asic_dbapp_db的vlan事件由portsorch进行同步,该部分涉及文件:
...