diff --git a/src/base/test/task_test_util.h b/src/base/test/task_test_util.h index 60440ea2504..8459cbe9601 100644 --- a/src/base/test/task_test_util.h +++ b/src/base/test/task_test_util.h @@ -90,7 +90,7 @@ do { \ #define TASK_UTIL_EXPECT_VECTOR_EQ(actual, expected) \ do { \ TASK_UTIL_EXPECT_EQ((expected).size(), (actual).size()); \ - for (int i = 0; i < (expected).size(); i++) { \ + for (int i = 0; i < (int)((expected).size()); i++) { \ TASK_UTIL_EXPECT_EQ((expected)[i], (actual)[i]); \ } \ } while (false) diff --git a/src/config/api-server/vnc_addr_mgmt.py b/src/config/api-server/vnc_addr_mgmt.py index c7b98948906..51249b9308c 100644 --- a/src/config/api-server/vnc_addr_mgmt.py +++ b/src/config/api-server/vnc_addr_mgmt.py @@ -119,6 +119,20 @@ def __str__(self): # end AddrMgmtInvalidGatewayIp +class AddrMgmtInvalidServiceNodeIp(AddrMgmtError): + + def __init__(self, subnet_val, service_address): + self.subnet_val = subnet_val + self.service_address = service_address + # end __init__ + + def __str__(self): + return "subnet(%s) has Invalid Service Node ip address(%s)" %\ + (self.subnet_val, self.service_address) + # end __str__ +# end AddrMgmtInvalidServiceNodeIp + + class AddrMgmtInvalidDnsNameServer(AddrMgmtError): def __init__(self, subnet_val, name_server): @@ -152,7 +166,7 @@ def set_db_conn(cls, db_conn): # end set_db_conn def __init__(self, name, prefix, prefix_len, - gw=None, enable_dhcp=True, + gw=None, service_address=None, enable_dhcp=True, dns_nameservers=None, alloc_pool_list=None, addr_from_start=False): @@ -184,6 +198,20 @@ def __init__(self, name, prefix, prefix_len, else: gw_ip = IPAddress(network.last - 1) + # check service_address + if service_address: + try: + service_node_address = IPAddress(service_address) + except AddrFormatError: + raise AddrMgmtInvalidServiceNodeIp(name, service_node_address) + + else: + # reserve a service address ip in subnet + if addr_from_start: + service_node_address = IPAddress(network.first + 2) + else: + service_node_address = IPAddress(network.last - 2) + # check dns_nameservers for nameserver in dns_nameservers or []: try: @@ -208,11 +236,12 @@ def __init__(self, name, prefix, prefix_len, 'end':int(IPAddress(alloc_pool['end']))} alloc_int_list.append(alloc_int) - # exclude gw_ip if it is within allocation-pool + # exclude gw_ip, service_node_address if they are within allocation-pool for alloc_int in alloc_int_list: if alloc_int['start'] <= int(gw_ip) <= alloc_int['end']: exclude.append(gw_ip) - break + if alloc_int['start'] <= int(service_node_address) <= alloc_int['end']: + exclude.append(service_node_address) self._db_conn.subnet_create_allocator(name, alloc_int_list, addr_from_start) @@ -225,6 +254,7 @@ def __init__(self, name, prefix, prefix_len, self._version = network.version self._exclude = exclude self.gw_ip = gw_ip + self.dns_server_address = service_node_address self._alloc_pool_list = alloc_pool_list self.enable_dhcp = enable_dhcp self.dns_nameservers = dns_nameservers @@ -344,6 +374,7 @@ def _get_subnet_dicts(self, vn_fq_name, vn_dict=None): for ipam_subnet in ipam_subnets: subnet_dict = copy.deepcopy(ipam_subnet['subnet']) subnet_dict['gw'] = ipam_subnet.get('default_gateway', None) + subnet_dict['dns_server_address'] = ipam_subnet.get('dns_server_address', None) subnet_dict['allocation_pools'] = \ ipam_subnet.get('allocation_pools', None) subnet_dict['enable_dhcp'] = ipam_subnet.get('enable_dhcp', True) @@ -372,6 +403,7 @@ def _create_subnet_objs(self, vn_fq_name_str, vn_dict): subnet['ip_prefix_len']) gateway_ip = ipam_subnet.get('default_gateway', None) + service_address = ipam_subnet.get('dns_server_address', None) allocation_pools = ipam_subnet.get('allocation_pools', None) dhcp_config = ipam_subnet.get('enable_dhcp', True) nameservers = ipam_subnet.get('dns_nameservers', None) @@ -379,13 +411,15 @@ def _create_subnet_objs(self, vn_fq_name_str, vn_dict): subnet_obj = Subnet( '%s:%s' % (vn_fq_name_str, subnet_name), subnet['ip_prefix'], str(subnet['ip_prefix_len']), - gw=gateway_ip, enable_dhcp=dhcp_config, + gw=gateway_ip, service_address=service_address, + enable_dhcp=dhcp_config, dns_nameservers=nameservers, alloc_pool_list=allocation_pools, addr_from_start=addr_start) self._subnet_objs[vn_fq_name_str][subnet_name] = \ subnet_obj ipam_subnet['default_gateway'] = str(subnet_obj.gw_ip) + ipam_subnet['dns_server_address'] = str(subnet_obj.dns_server_address) # end _create_subnet_objs def config_log(self, msg, level): @@ -436,8 +470,8 @@ def net_update_req(self, vn_fq_name, db_vn_dict, req_vn_dict, obj_uuid=None): # check db_subnet_dicts and req_subnet_dicts # following parameters are same for subnets present in both dicts - # 1. enable_dhcp, 2. default_gateway, 3. allocation_pool - # 4 dns_nameservers + # 1. enable_dhcp, 2. default_gateway, 3. dns_server_address + # 4. allocation_pool, 5. dns_nameservers for key in req_subnet_dicts.keys(): req_subnet = req_subnet_dicts[key] if key in db_subnet_dicts.keys(): @@ -446,6 +480,8 @@ def net_update_req(self, vn_fq_name, db_vn_dict, req_vn_dict, obj_uuid=None): req_subnet['enable_dhcp'] = True if (req_subnet['gw'] != db_subnet['gw']): raise AddrMgmtSubnetInvalid(vn_fq_name_str, key) + if (req_subnet['dns_server_address'] != db_subnet['dns_server_address']): + raise AddrMgmtSubnetInvalid(vn_fq_name_str, key) req_alloc_list = req_subnet['allocation_pools'] or [] db_alloc_list = db_subnet['allocation_pools'] or [] @@ -641,6 +677,16 @@ def net_check_subnet(self, db_vn_dict, req_vn_dict): err_msg = "gateway Ip of configured subnets conflicting " \ "in deciding forwarding mode for virtual network." return False, err_msg + + # check service address + service_address = ipam_subnet.get('dns_server_address', None) + if service_address is not None: + try: + service_node_address = IPAddress(service_address) + except AddrFormatError: + err_msg = "Invalid Dns Server Ip address:%s" \ + %(service_address) + return False, err_msg return True, "" # end net_check_subnet @@ -747,6 +793,7 @@ def ip_alloc_req(self, vn_fq_name, sub=None, asked_ip_addr=None, subnet_dict['ip_prefix'], subnet_dict['ip_prefix_len'], gw=subnet_dict['gw'], + service_address=subnet_dict['dns_server_address'], enable_dhcp=subnet_dict['enable_dhcp'], dns_nameservers=subnet_dict['dns_nameservers'], alloc_pool_list=subnet_dict['allocation_pools'], @@ -757,6 +804,8 @@ def ip_alloc_req(self, vn_fq_name, sub=None, asked_ip_addr=None, continue if asked_ip_addr == str(subnet_obj.gw_ip): return asked_ip_addr + if asked_ip_addr == str(subnet_obj.dns_server_address): + return asked_ip_addr if asked_ip_addr and not subnet_obj.ip_belongs(asked_ip_addr): continue try: @@ -792,6 +841,7 @@ def ip_alloc_notify(self, ip_addr, vn_fq_name): subnet_dict['ip_prefix'], subnet_dict['ip_prefix_len'], gw=subnet_dict['gw'], + service_address=subnet_dict['dns_server_address'], enable_dhcp=subnet_dict['enable_dhcp'], dns_nameservers=subnet_dict['dns_nameservers'], alloc_pool_list=subnet_dict['allocation_pools'], @@ -827,6 +877,7 @@ def ip_free_req(self, ip_addr, vn_fq_name, sub=None): subnet_dict['ip_prefix'], subnet_dict['ip_prefix_len'], gw=subnet_dict['gw'], + service_address=subnet_dict['dns_server_address'], enable_dhcp=subnet_dict['enable_dhcp'], dns_nameservers=subnet_dict['dns_nameservers'], alloc_pool_list=subnet_dict['allocation_pools'], @@ -861,6 +912,7 @@ def is_ip_allocated(self, ip_addr, vn_fq_name, sub=None): subnet_dict['ip_prefix'], subnet_dict['ip_prefix_len'], gw=subnet_dict['gw'], + service_address=subnet_dict['dns_server_address'], enable_dhcp=subnet_dict['enable_dhcp'], dns_nameservers=subnet_dict['dns_nameservers'], alloc_pool_list=subnet_dict['allocation_pools'], diff --git a/src/ifmap/ifmap_graph_walker.cc b/src/ifmap/ifmap_graph_walker.cc index cf3fb414790..5c80ce68bc2 100644 --- a/src/ifmap/ifmap_graph_walker.cc +++ b/src/ifmap/ifmap_graph_walker.cc @@ -244,6 +244,7 @@ void IFMapGraphWalker::AddNodesToWhitelist() { traversal_white_list_->include_vertex.insert("loadbalancer-pool"); traversal_white_list_->include_vertex.insert("loadbalancer-member"); traversal_white_list_->include_vertex.insert("loadbalancer-healthmonitor"); + traversal_white_list_->include_vertex.insert("subnet"); } void IFMapGraphWalker::AddLinksToWhitelist() { @@ -321,6 +322,8 @@ void IFMapGraphWalker::AddLinksToWhitelist() { "source=loadbalancer-pool,target=virtual-ip"); traversal_white_list_->include_edge.insert( "source=loadbalancer-pool,target=loadbalancer-member"); + traversal_white_list_->include_edge.insert( + "source=virtual-machine-interface,target=subnet"); // Manually add required links not picked by the // IFMapGraphTraversalFilterCalculator diff --git a/src/ksync/ksync_entry.h b/src/ksync/ksync_entry.h index 2ed6d3cc4a8..3ae49947254 100644 --- a/src/ksync/ksync_entry.h +++ b/src/ksync/ksync_entry.h @@ -99,6 +99,9 @@ class KSyncEntry { // Returns true if entry is resolved and referring entry can be written bool IsResolved(); + // Returns true if the entry data is resolved + virtual bool IsDataResolved() {return true;} + // User define KSync Response handler virtual void Response() { }; diff --git a/src/ksync/ksync_object.cc b/src/ksync/ksync_object.cc index e9639ae495e..d6d12dcb3c7 100644 --- a/src/ksync/ksync_object.cc +++ b/src/ksync/ksync_object.cc @@ -57,6 +57,19 @@ KSyncEntry *KSyncObject::Find(const KSyncEntry *key) { return NULL; } +KSyncEntry *KSyncObject::Next(const KSyncEntry *entry) { + Tree::const_iterator it; + if (entry == NULL) { + it = tree_.begin(); + } else { + it = tree_.iterator_to(*entry); + it++; + } + if (it != tree_.end()) { + return const_cast(it.operator->()); + } + return NULL; +} KSyncEntry *KSyncObject::CreateImpl(const KSyncEntry *key) { KSyncEntry *entry; if (need_index_) { @@ -160,6 +173,11 @@ void KSyncDBObject::UnregisterDb(DBTableBase *table) { table_ = NULL; } +KSyncDBObject::DBFilterResp KSyncDBObject::DBEntryFilter(const DBEntry *entry) { + // Default accept all + return DBFilterAccept; +} + void KSyncDBObject::set_test_id(DBTableBase::ListenerId id) { test_id_ = id; } @@ -193,8 +211,13 @@ void KSyncDBObject::Notify(DBTablePartBase *partition, DBEntryBase *e) { assert(table_ == table); DBState *state = entry->GetState(table, id_); KSyncDBEntry *ksync = static_cast(state); + DBFilterResp resp = DBFilterAccept; + + if (!entry->IsDeleted()) { + resp = DBEntryFilter(entry); + } - if (entry->IsDeleted()) { + if (entry->IsDeleted() || resp == DBFilterDelete) { // We may get duplicate delete notification in // case of db entry reuse // add -> change ->delete(Notify) -> change -> delete(Notify) @@ -204,6 +227,10 @@ void KSyncDBObject::Notify(DBTablePartBase *partition, DBEntryBase *e) { NotifyEvent(ksync, KSyncEntry::DEL_REQ); } } else { + if (resp == DBFilterIgnore) { + // DB filter tells us to ignore this Add/Change. + return; + } bool need_sync = false; if (ksync == NULL) { KSyncEntry *key, *found; @@ -218,7 +245,17 @@ void KSyncDBObject::Notify(DBTablePartBase *partition, DBEntryBase *e) { } delete key; entry->SetState(table, id_, ksync); - assert(ksync->GetDBEntry() == NULL); + DBEntry *old_db_entry = ksync->GetDBEntry(); + if (old_db_entry != NULL) { + // cleanup previous state id the old db entry is delete marked. + if (old_db_entry->IsDeleted()) { + CleanupOnDel(ksync); + } else { + // something wrong! two db entry in oper db points to same + // KSync entry. + assert(false); + } + } ksync->SetDBEntry(entry); need_sync = true; } @@ -241,6 +278,8 @@ bool KSyncEntry::IsResolved() { KSyncObject *obj = GetObject(); if (obj->IsIndexValid() && index_ == kInvalidIndex) return false; + if (IsDataResolved() == false) + return false; return ((state_ >= IN_SYNC) && (state_ < DEL_DEFER_SYNC)); } @@ -947,6 +986,7 @@ void KSyncObject::NotifyEvent(KSyncEntry *entry, KSyncEntry::KSyncEvent event) { break; case KSyncEntry::SYNC_WAIT: + dep_reval = true; state = KSyncSM_SyncWait(this, entry, event); break; @@ -1107,11 +1147,41 @@ KSyncObjectManager::~KSyncObjectManager() { SandeshTraceBufferPtr KSyncTraceBuf(SandeshTraceBufferCreate("KSync", 1000)); -void KSyncObjectManager::Init() { +KSyncObjectManager *KSyncObjectManager::Init() { singleton_ = new KSyncObjectManager(); + return singleton_; } void KSyncObjectManager::Shutdown() { delete singleton_; singleton_ = NULL; } + +// Create a dummy KSync Entry. This entry will all ways be in deferred state +// Any back-ref added to it will never get resolved. +// Can be used to defer an incomplete entry + +class KSyncDummyEntry : public KSyncEntry { +public: + KSyncDummyEntry() : KSyncEntry() { } + virtual ~KSyncDummyEntry() { } + virtual bool IsLess(const KSyncEntry &rhs) const { + return false; + } + std::string ToString() const { return "Dummy"; } + bool Add() { return false;} + bool Change() { return false; } + bool Delete() { return false; } + KSyncObject *GetObject() { return NULL; } + KSyncEntry *UnresolvedReference() { return NULL; } + bool IsDataResolved() {return false;} +private: + DISALLOW_COPY_AND_ASSIGN(KSyncDummyEntry); +}; + +KSyncEntry *KSyncObjectManager::default_defer_entry() { + if (default_defer_entry_.get() == NULL) { + default_defer_entry_.reset(new KSyncDummyEntry()); + } + return default_defer_entry_.get(); +} diff --git a/src/ksync/ksync_object.h b/src/ksync/ksync_object.h index 26630a2448e..e0443ecde74 100644 --- a/src/ksync/ksync_object.h +++ b/src/ksync/ksync_object.h @@ -108,6 +108,8 @@ class KSyncObject { void Delete(KSyncEntry *entry); // Query function. Key is in entry KSyncEntry *Find(const KSyncEntry *key); + // Get Next Function. + KSyncEntry *Next(const KSyncEntry *entry); // Query KSyncEntry for key in entry. Create temporary entry if not present KSyncEntry *GetReference(const KSyncEntry *key); @@ -156,6 +158,11 @@ class KSyncObject { // Special KSyncObject for DB client class KSyncDBObject : public KSyncObject { public: + enum DBFilterResp { + DBFilterAccept, // Accept DB Entry Add/Change for processing + DBFilterIgnore, // Ignore DB Entry Add/Change + DBFilterDelete // Ignore DB Entry Add/Change and clear previous state + }; // Create KSyncObject. DB Table will be registered later KSyncDBObject(); KSyncDBObject(int max_index); @@ -179,6 +186,8 @@ class KSyncDBObject : public KSyncObject { DBTableBase *GetDBTable() { return table_; } DBTableBase::ListenerId GetListenerId(DBTableBase *table); + // Function to filter DB Entries to be used. + virtual DBFilterResp DBEntryFilter(const DBEntry *entry); // Populate Key in KSyncEntry from DB Entry. // Used for lookup of KSyncEntry from DBEntry virtual KSyncEntry *DBToKSyncEntry(const DBEntry *entry) = 0; @@ -213,11 +222,13 @@ class KSyncObjectManager { ~KSyncObjectManager(); bool Process(KSyncObjectEvent *event); void Enqueue(KSyncObjectEvent *event); - static void Init(); + KSyncEntry *default_defer_entry(); + static KSyncObjectManager *Init(); static void Shutdown(); static void Unregister(KSyncObject *); private: WorkQueue *event_queue_; + std::auto_ptr default_defer_entry_; static KSyncObjectManager *singleton_; }; diff --git a/src/ksync/test/ksync_db_test.cc b/src/ksync/test/ksync_db_test.cc index 8a91fdbbee1..3411e48ce1b 100644 --- a/src/ksync/test/ksync_db_test.cc +++ b/src/ksync/test/ksync_db_test.cc @@ -40,32 +40,37 @@ class TestUT : public ::testing::Test { class Vlan : public DBEntry { public: struct VlanKey : public DBRequestKey { - VlanKey(uint16_t tag) : DBRequestKey(), tag_(tag) { }; + VlanKey(string name, uint16_t tag) : DBRequestKey(), name_(name), + tag_(tag) { }; virtual ~VlanKey() { }; + string name_; uint16_t tag_; }; - Vlan(uint16_t tag) : DBEntry(), tag_(tag) { }; + Vlan(string name, uint16_t tag) : DBEntry(), name_(name), tag_(tag) { }; virtual ~Vlan() { }; bool IsLess(const DBEntry &rhs) const { const Vlan &vlan = static_cast(rhs); - return tag_ < vlan.tag_; + return name_ < vlan.name_; }; virtual string ToString() const { return "Vlan"; }; virtual void SetKey(const DBRequestKey *k) { const VlanKey *key = static_cast(k); + name_ = key->name_; tag_ = key->tag_; }; virtual KeyPtr GetDBRequestKey() const { - VlanKey *key = new VlanKey(tag_); + VlanKey *key = new VlanKey(name_, tag_); return DBEntryBase::KeyPtr(key); }; uint16_t GetTag() const {return tag_;}; + string name() const {return name_;} private: + string name_; uint16_t tag_; friend class VlanTable; DISALLOW_COPY_AND_ASSIGN(Vlan); @@ -78,13 +83,13 @@ class VlanTable : public DBTable { virtual std::auto_ptr AllocEntry(const DBRequestKey *k) const { const Vlan::VlanKey *key = static_cast(k); - Vlan *vlan = new Vlan(key->tag_); + Vlan *vlan = new Vlan(key->name_, key->tag_); return std::auto_ptr(static_cast(vlan)); } virtual DBEntry *Add(const DBRequest *req) { Vlan::VlanKey *key = static_cast(req->key.get()); - Vlan *vlan = new Vlan(key->tag_); + Vlan *vlan = new Vlan(key->name_, key->tag_); return vlan; } @@ -251,7 +256,7 @@ KSyncDBObject *VlanKSyncEntry::GetObject() { TEST_F(DBKSyncTest, Basic) { DBRequest req; req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; - req.key.reset(new Vlan::VlanKey(10)); + req.key.reset(new Vlan::VlanKey("vlan10", 10)); req.data.reset(NULL); itbl->Enqueue(&req); @@ -263,7 +268,7 @@ TEST_F(DBKSyncTest, Basic) { EXPECT_EQ(VlanKSyncEntry::GetDelCount(), 0); req.oper = DBRequest::DB_ENTRY_DELETE; - req.key.reset(new Vlan::VlanKey(10)); + req.key.reset(new Vlan::VlanKey("vlan10", 10)); req.data.reset(NULL); itbl->Enqueue(&req); @@ -278,12 +283,12 @@ TEST_F(DBKSyncTest, Basic) { TEST_F(DBKSyncTest, AddDelCompress) { DBRequest req; req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; - req.key.reset(new Vlan::VlanKey(10)); + req.key.reset(new Vlan::VlanKey("vlan10", 10)); req.data.reset(NULL); itbl->Enqueue(&req); req.oper = DBRequest::DB_ENTRY_DELETE; - req.key.reset(new Vlan::VlanKey(10)); + req.key.reset(new Vlan::VlanKey("vlan10", 10)); req.data.reset(NULL); itbl->Enqueue(&req); @@ -299,7 +304,7 @@ TEST_F(DBKSyncTest, AddDelCompress) { TEST_F(DBKSyncTest, DuplicateDelete) { DBRequest req; req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; - req.key.reset(new Vlan::VlanKey(10)); + req.key.reset(new Vlan::VlanKey("vlan10", 10)); req.data.reset(NULL); itbl->Enqueue(&req); @@ -311,13 +316,13 @@ TEST_F(DBKSyncTest, DuplicateDelete) { ksync_vlan = VlanKSyncObject::GetKSyncObject()->Find(&v); req.oper = DBRequest::DB_ENTRY_DELETE; - req.key.reset(new Vlan::VlanKey(10)); + req.key.reset(new Vlan::VlanKey("vlan10", 10)); req.data.reset(NULL); itbl->Enqueue(&req); task_util::WaitForIdle(); req.oper = DBRequest::DB_ENTRY_DELETE; - req.key.reset(new Vlan::VlanKey(10)); + req.key.reset(new Vlan::VlanKey("vlan10", 10)); req.data.reset(NULL); itbl->Enqueue(&req); task_util::WaitForIdle(); @@ -334,7 +339,7 @@ TEST_F(DBKSyncTest, DuplicateDelete) { TEST_F(DBKSyncTest, Del_Ack_Wait_to_Temp) { DBRequest req; req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; - req.key.reset(new Vlan::VlanKey(10)); + req.key.reset(new Vlan::VlanKey("vlan10", 10)); req.data.reset(NULL); itbl->Enqueue(&req); @@ -349,7 +354,7 @@ TEST_F(DBKSyncTest, Del_Ack_Wait_to_Temp) { k_vlan->set_no_ack_trigger(false); ksync_vlan = NULL; req.oper = DBRequest::DB_ENTRY_DELETE; - req.key.reset(new Vlan::VlanKey(10)); + req.key.reset(new Vlan::VlanKey("vlan10", 10)); req.data.reset(NULL); itbl->Enqueue(&req); task_util::WaitForIdle(); @@ -363,14 +368,14 @@ TEST_F(DBKSyncTest, Del_Ack_Wait_to_Temp) { k_vlan->set_no_ack_trigger(true); req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; - req.key.reset(new Vlan::VlanKey(10)); + req.key.reset(new Vlan::VlanKey("vlan10", 10)); req.data.reset(NULL); itbl->Enqueue(&req); task_util::WaitForIdle(); EXPECT_EQ(ksync_vlan->GetState(), KSyncEntry::IN_SYNC); req.oper = DBRequest::DB_ENTRY_DELETE; - req.key.reset(new Vlan::VlanKey(10)); + req.key.reset(new Vlan::VlanKey("vlan10", 10)); req.data.reset(NULL); itbl->Enqueue(&req); task_util::WaitForIdle(); @@ -384,6 +389,51 @@ TEST_F(DBKSyncTest, Del_Ack_Wait_to_Temp) { EXPECT_EQ(VlanKSyncEntry::GetDelCount(), 2); } +TEST_F(DBKSyncTest, KSyncEntryRenewWithNewDBEntry) { + DBRequest req; + req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; + req.key.reset(new Vlan::VlanKey("vlan10", 10)); + req.data.reset(NULL); + itbl->Enqueue(&req); + + //Get a reference to vlan entry, to avoid deletion + task_util::WaitForIdle(); + VlanKSyncEntry v(10); + KSyncEntry::KSyncEntryPtr ksync_vlan; + ksync_vlan = VlanKSyncObject::GetKSyncObject()->Find(&v); + + req.oper = DBRequest::DB_ENTRY_DELETE; + req.key.reset(new Vlan::VlanKey("vlan10", 10)); + req.data.reset(NULL); + itbl->Enqueue(&req); + task_util::WaitForIdle(); + + // Delete pending due to reference + EXPECT_EQ(ksync_vlan->GetState(), KSyncEntry::DEL_DEFER_REF); + + req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; + req.key.reset(new Vlan::VlanKey("new_vlan10", 10)); + req.data.reset(NULL); + itbl->Enqueue(&req); + task_util::WaitForIdle(); + + // Ksync should move to in sync and new db entry. + EXPECT_EQ(ksync_vlan->GetState(), KSyncEntry::IN_SYNC); + ksync_vlan = NULL; + + req.oper = DBRequest::DB_ENTRY_DELETE; + req.key.reset(new Vlan::VlanKey("new_vlan10", 10)); + req.data.reset(NULL); + itbl->Enqueue(&req); + task_util::WaitForIdle(); + + EXPECT_EQ(adc_notification, 2); + EXPECT_EQ(del_notification, 2); + + EXPECT_EQ(VlanKSyncEntry::GetAddCount(), 1); + EXPECT_EQ(VlanKSyncEntry::GetDelCount(), 1); +} + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); LoggingInit(); diff --git a/src/vnsw/agent/SConscript b/src/vnsw/agent/SConscript index 7cad7ce617c..f0931e21735 100644 --- a/src/vnsw/agent/SConscript +++ b/src/vnsw/agent/SConscript @@ -84,6 +84,8 @@ env.Append(LIBPATH = MapBuildDir([ 'vnsw/agent/oper', 'vnsw/agent/pkt', 'vnsw/agent/services', + 'vnsw/agent/physical_devices/tables', + 'vnsw/agent/physical_devices/tsn', 'vnsw/agent/uve', 'vnsw/agent/vgw', 'vrouter/utils', @@ -143,6 +145,8 @@ env.Prepend(LIBS = [ 'ksync', 'nova_ins', 'nova_ins_thrift', + 'physical_devices', + 'tsn', 'uve', 'vgw', ]) diff --git a/src/vnsw/agent/cfg/cfg_init.cc b/src/vnsw/agent/cfg/cfg_init.cc index f87dde7be53..df633cc7c7e 100644 --- a/src/vnsw/agent/cfg/cfg_init.cc +++ b/src/vnsw/agent/cfg/cfg_init.cc @@ -153,6 +153,18 @@ void AgentConfig::RegisterDBClients(DB *db) { boost::bind(&GlobalVrouter::GlobalVrouterConfig, agent_->oper_db()->global_vrouter(), _1), -1); + cfg_listener_->Register + ("physical-interface", boost::bind(&VmInterface::PhysicalPortSync, + agent_->interface_table(), _1), -1); + + cfg_listener_->Register + ("logical-interface", boost::bind(&VmInterface::LogicalPortSync, + agent_->interface_table(), _1), -1); + + cfg_listener_->Register + ("subnet", boost::bind(&VmInterface::SubnetSync, + agent_->interface_table(), _1), -1); + cfg_vm_interface_table_ = (static_cast (IFMapTable::FindTable(agent_->db(), "virtual-machine-interface"))); assert(cfg_vm_interface_table_); @@ -208,6 +220,16 @@ void AgentConfig::RegisterDBClients(DB *db) { "interface-route-table"))); assert(cfg_route_table_); + cfg_subnet_table_ = (static_cast + (IFMapTable::FindTable(agent_->db(), + "subnet"))); + assert(cfg_route_table_); + + cfg_logical_port_table_ = (static_cast + (IFMapTable::FindTable(agent_->db(), + "logical-interface"))); + assert(cfg_logical_port_table_); + cfg_interface_client_->Init(); } diff --git a/src/vnsw/agent/cfg/cfg_init.h b/src/vnsw/agent/cfg/cfg_init.h index c56d0cecbab..b36b3aa77c5 100644 --- a/src/vnsw/agent/cfg/cfg_init.h +++ b/src/vnsw/agent/cfg/cfg_init.h @@ -57,6 +57,14 @@ class AgentConfig { return cfg_service_template_table_; } + IFMapAgentTable *cfg_subnet_table() const { + return cfg_subnet_table_; + } + + IFMapAgentTable *cfg_logical_port_table() const { + return cfg_logical_port_table_; + } + Agent *agent() const { return agent_; } CfgFilter *cfg_filter() const { return cfg_filter_.get(); } CfgListener *cfg_listener() const { return cfg_listener_.get(); } @@ -108,6 +116,8 @@ class AgentConfig { IFMapAgentTable *cfg_vm_port_vrf_table_; IFMapAgentTable *cfg_route_table_; IFMapAgentTable *cfg_service_template_table_; + IFMapAgentTable *cfg_subnet_table_; + IFMapAgentTable *cfg_logical_port_table_; DISALLOW_COPY_AND_ASSIGN(AgentConfig); }; diff --git a/src/vnsw/agent/cfg/cfg_interface_listener.cc b/src/vnsw/agent/cfg/cfg_interface_listener.cc index 6c5a557ccc5..20dcca42ca9 100644 --- a/src/vnsw/agent/cfg/cfg_interface_listener.cc +++ b/src/vnsw/agent/cfg/cfg_interface_listener.cc @@ -33,7 +33,7 @@ void InterfaceCfgClient::Notify(DBTablePartBase *partition, DBEntryBase *e) { if (entry->IsDeleted()) { VmInterface::Delete(agent->interface_table(), - entry->GetUuid()); + entry->GetUuid(), VmInterface::EXTERNAL); } else { uint16_t tx_vlan_id = VmInterface::kInvalidVlanId; uint16_t rx_vlan_id = VmInterface::kInvalidVlanId; @@ -44,11 +44,11 @@ void InterfaceCfgClient::Notify(DBTablePartBase *partition, DBEntryBase *e) { port = agent->params()->vmware_physical_port(); } - VmInterface::Add(agent->interface_table(), - entry->GetUuid(), entry->GetIfname(), - entry->ip_addr().to_v4(), entry->GetMacAddr(), - entry->vm_name(), entry->vm_project_uuid(), - tx_vlan_id, rx_vlan_id, port, entry->ip6_addr()); + VmInterface::NovaAdd(agent->interface_table(), entry->GetUuid(), + entry->GetIfname(), entry->ip_addr().to_v4(), + entry->GetMacAddr(), entry->vm_name(), + entry->vm_project_uuid(), tx_vlan_id, rx_vlan_id, + port, entry->ip6_addr()); IFMapNode *node = UuidToIFNode(entry->GetUuid()); if (node != NULL) { DBRequest req; diff --git a/src/vnsw/agent/cfg/cfg_listener.cc b/src/vnsw/agent/cfg/cfg_listener.cc index 0fb74482cbd..92aa12a47fa 100644 --- a/src/vnsw/agent/cfg/cfg_listener.cc +++ b/src/vnsw/agent/cfg/cfg_listener.cc @@ -145,7 +145,7 @@ AgentDBTable* CfgListener::GetOperDBTable(IFMapNode *node) { } const CfgTableListenerInfo *info = &loc->second; // Check for presence of ID_PERMS if configured - if (info->need_property_id_ > 0) { + if (info->need_property_id_ >= 0) { const IFMapObject *obj = node->GetObject(); const IFMapIdentifier *id = static_cast(obj); if (id->IsPropertySet(info->need_property_id_) == false) { @@ -170,7 +170,7 @@ CfgListener::NodeListenerCb CfgListener::GetCallback(IFMapNode *node) { const CfgListenerInfo *info = &it->second; // Check for presence of ID_PERMS if configured - if (info->need_property_id_ > 0) { + if (info->need_property_id_ >= 0) { const IFMapObject *obj = node->GetObject(); const IFMapIdentifier *id = static_cast(obj); if (id->IsPropertySet(info->need_property_id_) == false) { @@ -416,3 +416,29 @@ IFMapNode *CfgListener::FindAdjacentIFMapNode(const Agent *agent, return NULL; } + +// Invoke callback for each adjacent node of given "type" +uint32_t CfgListener::ForEachAdjacentIFMapNode(const Agent *agent, + IFMapNode *node, + const char *type, + AgentKey *key, + AgentData *data, + IFMapNodeCb cb) { + uint32_t count = 0; + IFMapAgentTable *table = static_cast(node->table()); + for (DBGraphVertex::adjacency_iterator iter = + node->begin(table->GetGraph()); + iter != node->end(table->GetGraph()); ++iter) { + IFMapNode *adj_node = static_cast(iter.operator->()); + if (SkipNode(adj_node)) { + continue; + } + + if (strcmp(adj_node->table()->Typename(), type) == 0) { + count++; + (cb)(agent, type, adj_node, key, data); + } + } + + return count; +} diff --git a/src/vnsw/agent/cfg/cfg_listener.h b/src/vnsw/agent/cfg/cfg_listener.h index 99cd6ef79e9..a82d4afd4a5 100644 --- a/src/vnsw/agent/cfg/cfg_listener.h +++ b/src/vnsw/agent/cfg/cfg_listener.h @@ -64,6 +64,17 @@ class CfgListener { bool SkipNode(IFMapNode *node); bool SkipNode(IFMapNode *node, IFMapAgentTable *table); + // Callback invoked for each IFMap neighbor node + typedef boost::function + IFMapNodeCb; + // Iterate thru all IFMap neighbor nodes and invoke callback for each + // neighbor of given type + uint32_t ForEachAdjacentIFMapNode(const Agent *agent, IFMapNode *node, + const char *name, AgentKey *key, + AgentData *data, IFMapNodeCb cb); + IFMapNode *FindAdjacentIFMapNode(const Agent *agent, IFMapNode *node, const char *name); private: diff --git a/src/vnsw/agent/cmn/agent.cc b/src/vnsw/agent/cmn/agent.cc index 828cd56456e..2fa0148c34e 100644 --- a/src/vnsw/agent/cmn/agent.cc +++ b/src/vnsw/agent/cmn/agent.cc @@ -220,6 +220,7 @@ void Agent::CopyConfig(AgentParam *params) { router_id_configured_ = false; } + compute_node_ip_ = router_id_; if (params_->tunnel_type() == "MPLSoUDP") TunnelType::SetDefaultType(TunnelType::MPLS_UDP); else if (params_->tunnel_type() == "VXLAN") @@ -231,6 +232,7 @@ void Agent::CopyConfig(AgentParam *params) { simulate_evpn_tor_ = params->simulate_evpn_tor(); debug_ = params_->debug(); test_mode_ = params_->test_mode(); + tsn_enabled_ = params_->isTsnEnabled(); } DiscoveryAgentClient *Agent::discovery_client() const { @@ -329,15 +331,21 @@ void Agent::InitXenLinkLocalIntf() { void Agent::InitPeers() { // Create peer entries - local_peer_.reset(new Peer(Peer::LOCAL_PEER, LOCAL_PEER_NAME)); - local_vm_peer_.reset(new Peer(Peer::LOCAL_VM_PEER, LOCAL_VM_PEER_NAME)); - linklocal_peer_.reset(new Peer(Peer::LINKLOCAL_PEER, LINKLOCAL_PEER_NAME)); - ecmp_peer_.reset(new Peer(Peer::ECMP_PEER, ECMP_PEER_NAME)); - vgw_peer_.reset(new Peer(Peer::VGW_PEER, VGW_PEER_NAME)); - multicast_peer_.reset(new Peer(Peer::MULTICAST_PEER, MULTICAST_PEER_NAME)); + local_peer_.reset(new Peer(Peer::LOCAL_PEER, LOCAL_PEER_NAME, false)); + local_vm_peer_.reset(new Peer(Peer::LOCAL_VM_PEER, LOCAL_VM_PEER_NAME, + false)); + linklocal_peer_.reset(new Peer(Peer::LINKLOCAL_PEER, LINKLOCAL_PEER_NAME, + false)); + ecmp_peer_.reset(new Peer(Peer::ECMP_PEER, ECMP_PEER_NAME, true)); + vgw_peer_.reset(new Peer(Peer::VGW_PEER, VGW_PEER_NAME, true)); + multicast_peer_.reset(new Peer(Peer::MULTICAST_PEER, MULTICAST_PEER_NAME, + false)); + multicast_tor_peer_.reset(new Peer(Peer::MULTICAST_TOR_PEER, + MULTICAST_TOR_PEER_NAME, false)); multicast_tree_builder_peer_.reset( new Peer(Peer::MULTICAST_FABRIC_TREE_BUILDER, - MULTICAST_FABRIC_TREE_BUILDER_NAME)); + MULTICAST_FABRIC_TREE_BUILDER_NAME, + false)); } Agent::Agent() : @@ -353,7 +361,8 @@ Agent::Agent() : acl_table_(NULL), mirror_table_(NULL), vrf_assign_table_(NULL), mirror_cfg_table_(NULL), intf_mirror_cfg_table_(NULL), intf_cfg_table_(NULL), router_id_(0), prefix_len_(0), - gateway_id_(0), xs_cfg_addr_(""), xs_idx_(0), xs_addr_(), xs_port_(), + gateway_id_(0), compute_node_ip_(0), xs_cfg_addr_(""), xs_idx_(0), + xs_addr_(), xs_port_(), xs_stime_(), xs_dns_idx_(0), dns_addr_(), dns_port_(), dss_addr_(""), dss_port_(0), dss_xs_instances_(0), discovery_client_name_(), @@ -367,7 +376,7 @@ Agent::Agent() : ksync_sync_mode_(true), mgmt_ip_(""), vxlan_network_identifier_mode_(AUTOMATIC), headless_agent_mode_(false), connection_state_(NULL), debug_(false), test_mode_(false), - init_done_(false), simulate_evpn_tor_(false) { + init_done_(false), simulate_evpn_tor_(false), tsn_enabled_(false) { assert(singleton_ == NULL); singleton_ = this; diff --git a/src/vnsw/agent/cmn/agent.h b/src/vnsw/agent/cmn/agent.h index 9086ca920fe..ee136a417a6 100644 --- a/src/vnsw/agent/cmn/agent.h +++ b/src/vnsw/agent/cmn/agent.h @@ -363,6 +363,7 @@ class Agent { } Ip4Address router_id() const {return router_id_;} + const Ip4Address *router_ip_ptr() const {return &router_id_;} void set_router_id(const Ip4Address &addr) { router_id_ = addr; set_router_id_configured(true); @@ -372,6 +373,11 @@ class Agent { router_id_configured_ = value; } + Ip4Address compute_node_ip() const {return compute_node_ip_;} + void set_compute_node_ip(const Ip4Address &addr) { + compute_node_ip_ = addr; + } + AgentSignal *agent_signal() const { return agent_signal_.get(); } // TODO: Should they be moved under controller/dns/cfg? @@ -632,6 +638,7 @@ class Agent { const Peer *ecmp_peer() const {return ecmp_peer_.get();} const Peer *vgw_peer() const {return vgw_peer_.get();} const Peer *multicast_peer() const {return multicast_peer_.get();} + const Peer *multicast_tor_peer() const {return multicast_tor_peer_.get();} const Peer *multicast_tree_builder_peer() const { return multicast_tree_builder_peer_.get();} @@ -716,6 +723,9 @@ class Agent { bool simulate_evpn_tor() const {return simulate_evpn_tor_;} void set_simulate_evpn_tor(bool mode) {simulate_evpn_tor_ = mode;} + bool tsn_enabled() const {return tsn_enabled_;} + void set_tsn_enabled(bool val) {tsn_enabled_ = val;} + IFMapAgentParser *ifmap_parser() const {return ifmap_parser_;} void set_ifmap_parser(IFMapAgentParser *parser) { ifmap_parser_ = parser; @@ -831,6 +841,12 @@ class Agent { Ip4Address router_id_; uint32_t prefix_len_; Ip4Address gateway_id_; + + // IP address on the compute node used by agent to run services such + // as metadata service. This is different than router_id when vhost0 + // is un-numbered interface in host-os + // The compute_node_ip_ is used only in adding Flow NAT rules. + Ip4Address compute_node_ip_; std::string xs_cfg_addr_; int8_t xs_idx_; std::string xs_addr_[MAX_XMPP_SERVERS]; @@ -863,6 +879,7 @@ class Agent { std::auto_ptr ecmp_peer_; std::auto_ptr vgw_peer_; std::auto_ptr multicast_peer_; + std::auto_ptr multicast_tor_peer_; std::auto_ptr multicast_tree_builder_peer_; std::auto_ptr agent_signal_; @@ -883,6 +900,7 @@ class Agent { bool test_mode_; bool init_done_; bool simulate_evpn_tor_; + bool tsn_enabled_; // Flow information uint32_t flow_table_size_; diff --git a/src/vnsw/agent/cmn/agent_db.cc b/src/vnsw/agent/cmn/agent_db.cc index fcfc39cb464..873ca460905 100644 --- a/src/vnsw/agent/cmn/agent_db.cc +++ b/src/vnsw/agent/cmn/agent_db.cc @@ -76,6 +76,7 @@ AgentDBEntry *AgentDBTable::Find(const DBRequestKey *key) { } void AgentDBTablePartition::Add(DBEntry *entry) { + entry->set_table_partition(static_cast(this)); DBTablePartition::Add(entry); static_cast(entry)->PostAdd(); } @@ -147,6 +148,10 @@ void AgentDBTable::Process(DBRequest &req) { static bool FlushNotify(DBTablePartBase *partition, DBEntryBase *e) { + if (e->IsDeleted()) { + return true; + } + DBRequest req(DBRequest::DB_ENTRY_DELETE); req.key = e->GetDBRequestKey(); (static_cast(e->get_table()))->Process(req); diff --git a/src/vnsw/agent/contrail-vrouter-agent.conf b/src/vnsw/agent/contrail-vrouter-agent.conf index 03fec46d5e8..cd5c55dc581 100644 --- a/src/vnsw/agent/contrail-vrouter-agent.conf +++ b/src/vnsw/agent/contrail-vrouter-agent.conf @@ -125,6 +125,12 @@ log_local=1 # Physical interface name to which virtual host interface maps to # physical_interface=vnet0 +# List of IP addresses assigned for the compute node other than vhost. Specify +# this only if vhost interface is un-numbered in host-os. Agent will use one +# of the compute_node_address to run services that need IP Address in host-os +# (like metadata...) +compute_node_address = 10.204.216.28 + # We can have multiple gateway sections with different indices in the # following format [GATEWAY-0] diff --git a/src/vnsw/agent/contrail/SConscript b/src/vnsw/agent/contrail/SConscript index add15629708..13baaa84f4a 100644 --- a/src/vnsw/agent/contrail/SConscript +++ b/src/vnsw/agent/contrail/SConscript @@ -71,6 +71,8 @@ buildinfo_dep_libs += MapBuildAgentLib([ 'openstack/libnova_ins_thrift.a', 'oper/libvnswoperdb.a', 'pkt/libpkt.a', 'diag/libdiag.a', + 'physical_devices/tables/libphysical_devices.a', + 'physical_devices/tsn/libtsn.a', 'services/libagent_services.a', 'uve/libstatsuve.a' ]) diff --git a/src/vnsw/agent/contrail/contrail_agent_init.cc b/src/vnsw/agent/contrail/contrail_agent_init.cc index 915b463c092..8d73293f8da 100644 --- a/src/vnsw/agent/contrail/contrail_agent_init.cc +++ b/src/vnsw/agent/contrail/contrail_agent_init.cc @@ -50,7 +50,6 @@ void ContrailAgentInit::CreateModules() { ksync_.reset(AgentObjectFactory::Create(agent())); agent()->set_ksync(ksync_.get()); - } void ContrailAgentInit::ConnectToController() { diff --git a/src/vnsw/agent/contrail/contrail_agent_init.h b/src/vnsw/agent/contrail/contrail_agent_init.h index ac47c565797..d8f4d75f995 100644 --- a/src/vnsw/agent/contrail/contrail_agent_init.h +++ b/src/vnsw/agent/contrail/contrail_agent_init.h @@ -14,6 +14,7 @@ class AgentParam; class DiagTable; class ServicesModule; class PktModule; +class TsnVrfListener; // The class to drive agent initialization. // Defines control parameters used to enable/disable agent features diff --git a/src/vnsw/agent/controller/controller_export.cc b/src/vnsw/agent/controller/controller_export.cc index 034cb930a11..af4b77a05c4 100644 --- a/src/vnsw/agent/controller/controller_export.cc +++ b/src/vnsw/agent/controller/controller_export.cc @@ -118,6 +118,8 @@ void RouteExport::UnicastNotify(AgentXmppChannel *bgp_xmpp_peer, DBTablePartBase *partition, DBEntryBase *e, Agent::RouteTableType type) { AgentRoute *route = static_cast(e); + AgentRouteTable *table = static_cast + (partition->parent()); State *state = static_cast(route->GetState(partition->parent(), id_)); AgentPath *path = route->FindLocalVmPortPath(); @@ -171,7 +173,8 @@ void RouteExport::UnicastNotify(AgentXmppChannel *bgp_xmpp_peer, state->Update(path); state->exported_ = AgentXmppChannel::ControllerSendRouteAdd(bgp_xmpp_peer, - static_cast(route), state->vn_, + static_cast(route), + path->NexthopIp(table->agent()), state->vn_, state->label_, path->GetTunnelBmap(), &path->sg_list(), type, state->path_preference_); } @@ -195,12 +198,33 @@ void RouteExport::UnicastNotify(AgentXmppChannel *bgp_xmpp_peer, } } +static const AgentPath *GetMulticastExportablePath(const Agent *agent, + const AgentRoute *route) { + const AgentPath *active_path = route->FindPath(agent->local_vm_peer()); + //If no loca peer, then look for tor peer as that should also result + //in export of route. + if (active_path == NULL) + active_path = route->FindPath(agent->multicast_tor_peer()); + //Subnet discard + if (active_path == NULL) { + const AgentPath *local_path = route->FindPath(agent->local_peer()); + if (local_path && local_path->is_subnet_discard()) { + return local_path; + } + } + return active_path; +} + static bool RouteCanDissociate(const AgentRoute *route) { bool can_dissociate = route->IsDeleted(); + Agent *agent = static_cast(route->get_table())-> + agent(); + const AgentPath *local_path = route->FindPath(agent->local_peer()); + if (local_path && local_path->is_subnet_discard()) { + return can_dissociate; + } if (route->is_multicast()) { - Agent *agent = static_cast(route->get_table())-> - agent(); - const AgentPath *active_path = route->FindPath(agent->local_vm_peer()); + const AgentPath *active_path = GetMulticastExportablePath(agent, route); if (active_path == NULL) return true; const NextHop *nh = active_path ? active_path->nexthop(agent) : NULL; @@ -216,10 +240,15 @@ void RouteExport::MulticastNotify(AgentXmppChannel *bgp_xmpp_peer, DBTablePartBase *partition, DBEntryBase *e) { AgentRoute *route = static_cast(e); + AgentRouteTable *table = static_cast + (partition->parent()); State *state = static_cast(route->GetState(partition->parent(), id_)); bool route_can_be_dissociated = RouteCanDissociate(route); const Agent *agent = bgp_xmpp_peer->agent(); + if (route->GetTableType() != Agent::LAYER2) + return; + if (route_can_be_dissociated && (state != NULL)) { if ((state->exported_ == true) && !(agent->simulate_evpn_tor())) { AgentXmppChannel::ControllerSendMcastRouteDelete(bgp_xmpp_peer, @@ -257,13 +286,19 @@ void RouteExport::MulticastNotify(AgentXmppChannel *bgp_xmpp_peer, return; } + // Dont register for multicast if vrouter is not present. If vrouter is + // not present, vhost interface will also be not present + if (route->GetTableType() == Agent::LAYER2 && + agent->vhost_interface() == NULL) { + return; + } + if (state == NULL) { state = new State(); route->SetState(partition->parent(), id_, state); } if (!route_can_be_dissociated) { - if (!(agent->simulate_evpn_tor()) && ((state->exported_ == false) || (state->force_chg_ == true))) { //Sending 255.255.255.255 for fabric tree @@ -278,7 +313,7 @@ void RouteExport::MulticastNotify(AgentXmppChannel *bgp_xmpp_peer, } //Sending ff:ff:ff:ff:ff:ff for evpn replication - const AgentPath *active_path = route->FindPath(agent->local_vm_peer()); + const AgentPath *active_path = GetMulticastExportablePath(agent, route); //const AgentPath *active_path = route->GetActivePath(); TunnelType::Type old_tunnel_type = state->tunnel_type_; uint32_t old_label = state->label_; @@ -301,11 +336,9 @@ void RouteExport::MulticastNotify(AgentXmppChannel *bgp_xmpp_peer, withdraw = true; } if (withdraw) { - AgentXmppChannel::ControllerSendEvpnRouteDelete(bgp_xmpp_peer, - route, - state->vn_, - withdraw_label, - state->tunnel_type_); + AgentXmppChannel::ControllerSendEvpnRouteDelete + (bgp_xmpp_peer, route, state->vn_, withdraw_label, + state->tunnel_type_); state->evpn_exported_ = false; } } @@ -328,11 +361,11 @@ void RouteExport::MulticastNotify(AgentXmppChannel *bgp_xmpp_peer, state->vn_ = route->dest_vn_name(); if (associate) { state->evpn_exported_ = - AgentXmppChannel::ControllerSendEvpnRouteAdd(bgp_xmpp_peer, - route, - route->dest_vn_name(), - state->label_, - TunnelType::AllType()); + AgentXmppChannel::ControllerSendEvpnRouteAdd + (bgp_xmpp_peer, route, + active_path->NexthopIp(table->agent()), + route->dest_vn_name(), state->label_, + TunnelType::GetTunnelBmap(state->tunnel_type_)); } else { state->evpn_exported_ = AgentXmppChannel::ControllerSendEvpnRouteDelete(bgp_xmpp_peer, diff --git a/src/vnsw/agent/controller/controller_peer.cc b/src/vnsw/agent/controller/controller_peer.cc index bbe07fa61df..acbf40fff0d 100644 --- a/src/vnsw/agent/controller/controller_peer.cc +++ b/src/vnsw/agent/controller/controller_peer.cc @@ -380,7 +380,8 @@ void AgentXmppChannel::ReceiveMulticastUpdate(XmlPugi *pugi) { nh_label >> label; TunnelType::TypeBmap encap = GetMcastTypeBitmap(nh.tunnel_encapsulation_list); - olist.push_back(OlistTunnelEntry(label, addr.to_v4(), encap)); + olist.push_back(OlistTunnelEntry(nil_uuid(), label, + addr.to_v4(), encap)); } MulticastHandler::ModifyFabricMembers( @@ -540,6 +541,18 @@ void AgentXmppChannel::AddEcmpRoute(string vrf_name, Ip4Address prefix_addr, MplsLabel *mpls = agent_->mpls_table()->FindMplsLabel(label); if (mpls != NULL) { + if (mpls->nexthop()->GetType() == NextHop::VRF) { + BgpPeer *bgp_peer = bgp_peer_id(); + ClonedLocalPath *data = + new ClonedLocalPath(unicast_sequence_number(), this, + label, item->entry.virtual_network, + item->entry.security_group_list.security_group); + rt_table->AddClonedLocalPathReq(bgp_peer, vrf_name, + prefix_addr, + prefix_len, data); + return; + } + DBEntryBase::KeyPtr key = mpls->nexthop()->GetDBRequestKey(); NextHopKey *nh_key = static_cast(key.release()); if (nh_key->GetType() != NextHop::COMPOSITE) { @@ -602,7 +615,8 @@ void AgentXmppChannel::AddMulticastEvpnRoute(string vrf_name, int label = item->entry.olist.next_hop[i].label; TunnelType::TypeBmap encap = GetEnetTypeBitmap(item-> entry.olist.next_hop[i].tunnel_encapsulation_list); - olist.push_back(OlistTunnelEntry(label, addr.to_v4(), encap)); + olist.push_back(OlistTunnelEntry(nil_uuid(), label, + addr.to_v4(), encap)); } CONTROLLER_TRACE(Trace, GetBgpPeerName(), "Composite", @@ -879,6 +893,26 @@ void AgentXmppChannel::AddRemoteRoute(string vrf_name, IpAddress prefix_addr, AddEcmpRoute(vrf_name, prefix_addr.to_v4(), prefix_len, item); break; } + case NextHop::VRF: { + //In case of TOR/vCPE with a logical interface vlan1, + //example subnet 1.1.1.0/24 may be reachable on logical + //interface vlan1. Path added by local vm peer would point to + //resolve NH, so that if any path hits this route, ARP resolution + //can begin, and the label exported for this route would point to + //table nexthop. + //Hence existing logic of picking up nexthop from mpls label to + //nexthop, will not work. We have added a special path where we + //pick nexthop from local vm path, instead of BGP + BgpPeer *bgp_peer = bgp_peer_id(); + ClonedLocalPath *data = + new ClonedLocalPath(unicast_sequence_number(), this, + label, item->entry.virtual_network, + item->entry.security_group_list.security_group); + rt_table->AddClonedLocalPathReq(bgp_peer, vrf_name, + prefix_addr.to_v4(), + prefix_len, data); + break; + } default: CONTROLLER_TRACE(Trace, GetBgpPeerName(), vrf_name, @@ -1594,6 +1628,7 @@ bool AgentXmppChannel::ControllerSendV4V6UnicastRouteCommon(AgentRoute *route, } bool AgentXmppChannel::ControllerSendEvpnRouteCommon(AgentRoute *route, + const Ip4Address *nh_ip, std::string vn, uint32_t label, uint32_t tunnel_bmap, @@ -1626,11 +1661,9 @@ bool AgentXmppChannel::ControllerSendEvpnRouteCommon(AgentRoute *route, item.entry.nlri.address = rstr.str(); assert(item.entry.nlri.address != "0.0.0.0"); - string rtr(agent_->router_id().to_string()); - autogen::EnetNextHopType nh; nh.af = Address::INET; - nh.address = rtr; + nh.address = nh_ip->to_string(); nh.label = label; item.entry.nlri.ethernet_tag = 0; @@ -1825,6 +1858,7 @@ bool AgentXmppChannel::ControllerSendMcastRouteCommon(AgentRoute *route, bool AgentXmppChannel::ControllerSendEvpnRouteAdd(AgentXmppChannel *peer, AgentRoute *route, + const Ip4Address *nh_ip, std::string vn, uint32_t label, uint32_t tunnel_bmap) { @@ -1834,6 +1868,7 @@ bool AgentXmppChannel::ControllerSendEvpnRouteAdd(AgentXmppChannel *peer, route->vrf()->GetName(), route->ToString(), true, label); return (peer->ControllerSendEvpnRouteCommon(route, + nh_ip, vn, label, tunnel_bmap, @@ -1850,7 +1885,9 @@ bool AgentXmppChannel::ControllerSendEvpnRouteDelete(AgentXmppChannel *peer, CONTROLLER_TRACE(RouteExport, peer->GetBgpPeerName(), route->vrf()->GetName(), route->ToString(), false, label); + Ip4Address nh_ip = Ip4Address(0); return (peer->ControllerSendEvpnRouteCommon(route, + &nh_ip, vn, label, tunnel_bmap, @@ -1859,6 +1896,7 @@ bool AgentXmppChannel::ControllerSendEvpnRouteDelete(AgentXmppChannel *peer, bool AgentXmppChannel::ControllerSendRouteAdd(AgentXmppChannel *peer, AgentRoute *route, + const Ip4Address *nexthop_ip, std::string vn, uint32_t label, TunnelType::TypeBmap bmap, @@ -1883,7 +1921,7 @@ bool AgentXmppChannel::ControllerSendRouteAdd(AgentXmppChannel *peer, type); } if (type == Agent::LAYER2) { - ret = peer->ControllerSendEvpnRouteCommon(route, vn, + ret = peer->ControllerSendEvpnRouteCommon(route, nexthop_ip, vn, label, bmap, true); } return ret; @@ -1917,7 +1955,8 @@ bool AgentXmppChannel::ControllerSendRouteDelete(AgentXmppChannel *peer, type); } if (type == Agent::LAYER2) { - ret = peer->ControllerSendEvpnRouteCommon(route, vn, + Ip4Address nh_ip(0); + ret = peer->ControllerSendEvpnRouteCommon(route, &nh_ip, vn, label, bmap, false); } return ret; diff --git a/src/vnsw/agent/controller/controller_peer.h b/src/vnsw/agent/controller/controller_peer.h index 0c3d8361ad1..9000a105fc3 100644 --- a/src/vnsw/agent/controller/controller_peer.h +++ b/src/vnsw/agent/controller/controller_peer.h @@ -61,6 +61,7 @@ class AgentXmppChannel { //Add to control-node static bool ControllerSendRouteAdd(AgentXmppChannel *peer, AgentRoute *route, + const Ip4Address *nexthop_ip, std::string vn, uint32_t label, uint32_t tunnel_bmap, @@ -69,6 +70,7 @@ class AgentXmppChannel { const PathPreference &path_preference); static bool ControllerSendEvpnRouteAdd(AgentXmppChannel *peer, AgentRoute *route, + const Ip4Address *nexthop_ip, std::string vn, uint32_t mpls_label, uint32_t tunnel_bmap); @@ -127,6 +129,7 @@ class AgentXmppChannel { bool associate, Agent::RouteTableType type); bool ControllerSendEvpnRouteCommon(AgentRoute *route, + const Ip4Address *nexthop_ip, std::string vn, uint32_t mpls_label, uint32_t tunnel_bmap, diff --git a/src/vnsw/agent/controller/controller_route_path.cc b/src/vnsw/agent/controller/controller_route_path.cc index ebdf6b31ef9..040abbf5004 100644 --- a/src/vnsw/agent/controller/controller_route_path.cc +++ b/src/vnsw/agent/controller/controller_route_path.cc @@ -61,7 +61,8 @@ bool ControllerEcmpRoute::IsPeerValid() const { return CheckPeerValidity(channel(), sequence_number()); } -bool ControllerEcmpRoute::AddChangePath(Agent *agent, AgentPath *path) { +bool ControllerEcmpRoute::AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt) { CompositeNHKey *comp_key = static_cast(nh_req_.key.get()); //Reorder the component NH list, and add a reference to local composite mpls //label if any @@ -100,7 +101,8 @@ bool ControllerVmRoute::IsPeerValid() const { return CheckPeerValidity(channel(), sequence_number()); } -bool ControllerVmRoute::AddChangePath(Agent *agent, AgentPath *path) { +bool ControllerVmRoute::AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt) { bool ret = false; NextHop *nh = NULL; SecurityGroupList path_sg_list; @@ -220,3 +222,78 @@ ControllerInetInterfaceRoute::ControllerInetInterfaceRoute(const InetInterfaceKe bool ControllerInetInterfaceRoute::IsPeerValid() const { return CheckPeerValidity(channel_, sequence_number_); } + +bool ClonedLocalPath::AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt) { + bool ret = false; + const AgentPath *local_path = rt->FindLocalVmPortPath(); + + path->ChangeNH(agent, NULL); + if (!local_path) { + MplsLabel *mpls = agent->mpls_table()->FindMplsLabel(mpls_label_); + if (!mpls) { + return false; + } + + //Do a route lookup in native VRF + assert(mpls->nexthop()->GetType() == NextHop::VRF); + const VrfNH *vrf_nh = static_cast(mpls->nexthop()); + const InetUnicastRouteEntry *uc_rt = + static_cast(rt); + const AgentRoute *rt = vrf_nh->GetVrf()->GetUcRoute(uc_rt->addr()); + if (rt == NULL) { + return false; + } + local_path = rt->FindLocalVmPortPath(); + if (!local_path) { + return false; + } + } + + if (path->dest_vn_name() != vn_) { + path->set_dest_vn_name(vn_); + ret = true; + } + path->set_unresolved(false); + + if (path->sg_list() != sg_list_) { + path->set_sg_list(sg_list_); + ret = true; + } + + path->set_tunnel_bmap(local_path->tunnel_bmap()); + TunnelType::Type new_tunnel_type = + TunnelType::ComputeType(path->tunnel_bmap()); + if (new_tunnel_type == TunnelType::VXLAN && + local_path->vxlan_id() == VxLanTable::kInvalidvxlan_id) { + new_tunnel_type = TunnelType::ComputeType(TunnelType::MplsType()); + } + + if (path->tunnel_type() != new_tunnel_type) { + path->set_tunnel_type(new_tunnel_type); + ret = true; + } + + // If policy force-enabled in request, enable policy + path->set_force_policy(local_path->force_policy()); + + if (path->label() != local_path->label()) { + path->set_label(local_path->label()); + ret = true; + } + + if (path->vxlan_id() != local_path->vxlan_id()) { + path->set_vxlan_id(local_path->vxlan_id()); + ret = true; + } + + NextHop *nh = const_cast(local_path->nexthop(agent)); + if (path->ChangeNH(agent, nh) == true) { + ret = true; + } + return ret; +} + +bool ClonedLocalPath::IsPeerValid() const { + return CheckPeerValidity(channel_, sequence_number_); +} diff --git a/src/vnsw/agent/controller/controller_route_path.h b/src/vnsw/agent/controller/controller_route_path.h index 893fa20146a..8ff90a9ff38 100644 --- a/src/vnsw/agent/controller/controller_route_path.h +++ b/src/vnsw/agent/controller/controller_route_path.h @@ -85,7 +85,8 @@ class ControllerVmRoute : public ControllerPeerPath { ControllerVmRoute(const Peer *peer) : ControllerPeerPath(peer) { } virtual ~ControllerVmRoute() { } - virtual bool AddChangePath(Agent *agent, AgentPath *path); + virtual bool AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt); virtual string ToString() const {return "remote VM";} virtual bool IsPeerValid() const; const SecurityGroupList &sg_list() const {return sg_list_;} @@ -127,7 +128,8 @@ class ControllerEcmpRoute : public ControllerPeerPath { {nh_req_.Swap(&nh_req);} virtual ~ControllerEcmpRoute() { } - virtual bool AddChangePath(Agent *agent, AgentPath *path); + virtual bool AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *); virtual string ToString() const {return "inet4 ecmp";} virtual bool IsPeerValid() const; @@ -209,4 +211,26 @@ class ControllerVlanNhRoute : public VlanNhRoute { DISALLOW_COPY_AND_ASSIGN(ControllerVlanNhRoute); }; +class ClonedLocalPath : public AgentRouteData { +public: + ClonedLocalPath(uint64_t seq, const AgentXmppChannel *channel, + uint32_t label, const std::string &vn, + const SecurityGroupList &sg_list): + AgentRouteData(false), sequence_number_(seq), + channel_(channel), mpls_label_(label), vn_(vn), sg_list_(sg_list) {} + virtual ~ClonedLocalPath() {} + virtual bool IsPeerValid() const; + virtual bool AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt); + virtual std::string ToString() const { + return "Nexthop cloned from local path"; + } +private: + uint64_t sequence_number_; + const AgentXmppChannel *channel_; + uint32_t mpls_label_; + const std::string vn_; + const SecurityGroupList sg_list_; + DISALLOW_COPY_AND_ASSIGN(ClonedLocalPath); +}; #endif //controller_route_path_hpp diff --git a/src/vnsw/agent/diag/test/test_ping.cc b/src/vnsw/agent/diag/test/test_ping.cc index 02c3807d3f2..d78c7e18a61 100644 --- a/src/vnsw/agent/diag/test/test_ping.cc +++ b/src/vnsw/agent/diag/test/test_ping.cc @@ -95,7 +95,7 @@ class DiagTest : public ::testing::Test { mac.ToArray(eth->ether_shost, sizeof(eth->ether_shost)); agent_hdr *agent = (agent_hdr *)(eth + 1); - int intf_id = ntohs(agent->hdr_ifindex); + std::size_t intf_id = ntohs(agent->hdr_ifindex); LOG(DEBUG, "Diag Callback; Agent index : " << ntohs(agent->hdr_ifindex) << " Interface index : " << GetItfId(0) << " " << GetItfId(1)); diff --git a/src/vnsw/agent/init/agent_init.cc b/src/vnsw/agent/init/agent_init.cc index 6b2914f0384..a7f6ab472e4 100644 --- a/src/vnsw/agent/init/agent_init.cc +++ b/src/vnsw/agent/init/agent_init.cc @@ -20,6 +20,7 @@ #include #include #include +#include #include "agent_init.h" @@ -54,7 +55,7 @@ string AgentInit::ModuleName() { } string AgentInit::AgentName() { - return agent_param_->host_name(); + return agent_param_->agent_name(); } string AgentInit::InstanceId() { @@ -69,14 +70,15 @@ int AgentInit::Start() { TaskScheduler::Initialize(); } agent_->set_task_scheduler(TaskScheduler::GetInstance()); + + // Copy tunable parameters into agent_ + agent_->CopyConfig(agent_param_); + string module_name = ModuleName(); agent_->set_discovery_client_name(module_name); agent_->set_agent_name(AgentName()); agent_->set_instance_id(InstanceId()); - // Copy tunable parameters into agent_ - agent_->CopyConfig(agent_param_); - LoggingInit(agent_param_->log_file(), agent_param_->log_file_size(), agent_param_->log_files_count(), agent_param_->use_syslog(), agent_param_->syslog_facility(), module_name); @@ -150,8 +152,13 @@ void AgentInit::CreateModulesBase() { if (enable_controller_) { controller_.reset(new VNController(agent())); + agent_->set_controller(controller_.get()); + } + + if (agent_->tsn_enabled()) { + device_manager_.reset(new PhysicalDeviceManager(agent())); + agent_->set_device_manager(device_manager_.get()); } - agent_->set_controller(controller_.get()); CreateModules(); } @@ -166,6 +173,10 @@ void AgentInit::CreateDBTablesBase() { } CreateDBTables(); + + if (agent_->tsn_enabled()) { + device_manager_->CreateDBTables(agent_->db()); + } } void AgentInit::RegisterDBClientsBase() { @@ -178,6 +189,10 @@ void AgentInit::RegisterDBClientsBase() { } RegisterDBClients(); + + if (agent_->tsn_enabled()) { + device_manager_->RegisterDBClients(); + } } void AgentInit::InitModulesBase() { @@ -190,6 +205,10 @@ void AgentInit::InitModulesBase() { } InitModules(); + + if (agent_->tsn_enabled()) { + device_manager_->Init(); + } } void AgentInit::CreateVrfBase() { @@ -210,7 +229,6 @@ void AgentInit::CreateVrfBase() { void AgentInit::CreateNextHopsBase() { DiscardNH::Create(); - ResolveNH::Create(); DiscardNHKey key; NextHop *nh = static_cast diff --git a/src/vnsw/agent/init/agent_init.h b/src/vnsw/agent/init/agent_init.h index 5c18c2c3cf7..504160e5c5f 100644 --- a/src/vnsw/agent/init/agent_init.h +++ b/src/vnsw/agent/init/agent_init.h @@ -13,6 +13,7 @@ class AgentParam; class DiagTable; class ServicesModule; class PktModule; +class PhysicalDeviceManager; // The class to drive agent initialization. Does init of basic modules // Daemons should derive from AgentInit class and tune / implement virtual @@ -161,6 +162,7 @@ class AgentInit { bool enable_controller_; std::auto_ptr controller_; + std::auto_ptr device_manager_; DISALLOW_COPY_AND_ASSIGN(AgentInit); }; diff --git a/src/vnsw/agent/init/agent_param.cc b/src/vnsw/agent/init/agent_param.cc index 2dd89c57590..159a85b989c 100644 --- a/src/vnsw/agent/init/agent_param.cc +++ b/src/vnsw/agent/init/agent_param.cc @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -271,6 +272,29 @@ void AgentParam::ParseCollector() { } } +void AgentParam::BuildAddressList(const string &val) { + compute_node_address_list_.clear(); + if (val.empty()) { + return; + } + + vector tokens; + boost::split(tokens, val, boost::is_any_of(" ")); + vector::iterator it = tokens.begin(); + while (it != tokens.end()) { + std::string str = *it; + ++it; + + boost::algorithm::trim(str); + Ip4Address addr; + if (GetIpAddress(str, &addr)) { + compute_node_address_list_.push_back(addr); + } else { + LOG(ERROR, "Error in parsing address " << *it); + } + } +} + void AgentParam::ParseVirtualHost() { boost::system::error_code ec; optional opt_str; @@ -279,7 +303,7 @@ void AgentParam::ParseVirtualHost() { if (opt_str = tree_.get_optional("VIRTUAL-HOST-INTERFACE.ip")) { ec = Ip4PrefixParse(opt_str.get(), &vhost_.addr_, &vhost_.plen_); - if (ec != 0 || vhost_.plen_ >= 32) { + if (ec != 0 || vhost_.plen_ > 32) { cout << "Error in config file <" << config_file_ << ">. Error parsing vhost ip-address from <" << opt_str.get() << ">\n"; @@ -294,8 +318,13 @@ void AgentParam::ParseVirtualHost() { } } - GetValueFromTree(eth_port_, + GetValueFromTree(eth_port_, "VIRTUAL-HOST-INTERFACE.physical_interface"); + + if (opt_str = tree_.get_optional + ("VIRTUAL-HOST-INTERFACE.compute_node_address")) { + BuildAddressList(opt_str.get()); + } } void AgentParam::ParseDiscovery() { @@ -358,6 +387,9 @@ void AgentParam::ParseDefaultSection() { optional opt_str; optional opt_uint; + GetValueFromTree(host_name_, "DEFAULT.hostname"); + GetValueFromTree(agent_name_, "DEFAULT.agent_name"); + if (!GetValueFromTree(http_server_port_, "DEFAULT.http_server_port")) { http_server_port_ = ContrailPorts::HttpPortAgent(); @@ -372,8 +404,6 @@ void AgentParam::ParseDefaultSection() { flow_cache_timeout_ = Agent::kDefaultFlowCacheTimeout; } - GetValueFromTree(host_name_, "DEFAULT.hostname"); - if (!GetValueFromTree(log_level_, "DEFAULT.log_level")) { log_level_ = "SYS_DEBUG"; } @@ -443,6 +473,12 @@ void AgentParam::ParseHeadlessMode() { } } +void AgentParam::ParseTsnMode() { + if (!GetValueFromTree(enable_tsn_, "DEFAULT.tsn")) { + enable_tsn_ = false; + } +} + void AgentParam::ParseSimulateEvpnTor() { if (!GetValueFromTree(simulate_evpn_tor_, "DEFAULT.simulate_evpn_tor")) { @@ -547,6 +583,7 @@ void AgentParam::ParseDefaultSectionArguments GetOptValue(var_map, flow_cache_timeout_, "DEFAULT.flow_cache_timeout"); GetOptValue(var_map, host_name_, "DEFAULT.hostname"); + GetOptValue(var_map, agent_name_, "DEFAULT.agent_name"); GetOptValue(var_map, http_server_port_, "DEFAULT.http_server_port"); GetOptValue(var_map, log_category_, "DEFAULT.log_category"); @@ -589,6 +626,11 @@ void AgentParam::ParseHeadlessModeArguments GetOptValue(var_map, headless_mode_, "DEFAULT.headless_mode"); } +void AgentParam::ParseTsnModeArguments + (const boost::program_options::variables_map &var_map) { + GetOptValue(var_map, enable_tsn_, "DEFAULT.tsn_mode"); +} + void AgentParam::ParseServiceInstanceArguments (const boost::program_options::variables_map &var_map) { GetOptValue(var_map, si_netns_command_, "SERVICE-INSTANCE.netns_command"); @@ -604,6 +646,7 @@ void AgentParam::ParseServiceInstanceArguments void AgentParam::InitFromSystem() { boost::system::error_code error; host_name_ = boost::asio::ip::host_name(error); + agent_name_ = host_name_; struct stat fstat; if (stat("/proc/xen", &fstat) == 0) { @@ -641,6 +684,7 @@ void AgentParam::InitFromConfig() { ParseHeadlessMode(); ParseSimulateEvpnTor(); ParseServiceInstance(); + ParseTsnMode(); cout << "Config file <" << config_file_ << "> parsing completed.\n"; return; } @@ -659,6 +703,7 @@ void AgentParam::InitFromArguments() { ParseMetadataProxyArguments(var_map_); ParseHeadlessModeArguments(var_map_); ParseServiceInstanceArguments(var_map_); + ParseTsnModeArguments(var_map_); return; } @@ -716,7 +761,11 @@ void AgentParam::ComputeFlowLimits() { } } -static bool ValidateInterface(bool test_mode, const std::string &ifname) { +static bool ValidateInterface(bool test_mode, const std::string &ifname, + bool *no_arp, string *eth_encap) { + *no_arp = false; + *eth_encap = ""; + if (test_mode) { return true; } @@ -726,7 +775,7 @@ static bool ValidateInterface(bool test_mode, const std::string &ifname) { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, ifname.c_str(), IF_NAMESIZE); - int err = ioctl(fd, SIOCGIFHWADDR, (void *)&ifr); + int err = ioctl(fd, SIOCGIFFLAGS, (void *)&ifr); close (fd); if (err < 0) { @@ -735,6 +784,22 @@ static bool ValidateInterface(bool test_mode, const std::string &ifname) { return false; } + if ((ifr.ifr_flags & IFF_NOARP)) { + *no_arp = true; + } + + char fname[128]; + snprintf(fname, 128, "/sys/class/net/%s/type", ifname.c_str()); + FILE *f = fopen(fname, "r"); + if (f) { + int type; + if (fscanf(f, "%d", &type) >= 0) { + if (type == ARPHRD_NONE) { + *eth_encap = "none"; + } + } + } + return true; } @@ -745,8 +810,10 @@ int AgentParam::Validate() { return (EINVAL); } + bool no_arp; + string encap; // Check if interface is already present - if (ValidateInterface(test_mode_, vhost_.name_) == false) { + if (ValidateInterface(test_mode_, vhost_.name_, &no_arp, &encap) == false) { return (ENODEV); } @@ -757,7 +824,8 @@ int AgentParam::Validate() { } // Check if interface is already present - if (ValidateInterface(test_mode_, eth_port_) == false) { + if (ValidateInterface(test_mode_, eth_port_, ð_port_no_arp_, + ð_port_encap_type_) == false) { return (ENODEV); } @@ -769,7 +837,8 @@ int AgentParam::Validate() { return (EINVAL); } - if (ValidateInterface(test_mode_, vmware_physical_port_) == false) { + if (ValidateInterface(test_mode_, vmware_physical_port_, &no_arp, + &encap) == false) { return (ENODEV); } } @@ -805,6 +874,10 @@ void AgentParam::LogConfig() const { << "/" << vhost_.plen_); LOG(DEBUG, "vhost gateway : " << vhost_.gw_.to_string()); LOG(DEBUG, "Ethernet port : " << eth_port_); + LOG(DEBUG, "Ethernet Encap Type : " << eth_port_encap_type_); + if (eth_port_no_arp_) { + LOG(DEBUG, "Ethernet No-ARP : " << "TRUE"); + } LOG(DEBUG, "XMPP Server-1 : " << xmpp_server_1_); LOG(DEBUG, "XMPP Server-2 : " << xmpp_server_2_); LOG(DEBUG, "DNS Server-1 : " << dns_server_1_); @@ -848,6 +921,10 @@ void AgentParam::LogConfig() const { LOG(DEBUG, "Vmware mode : Esxi_Neutron"); } } + + if (enable_tsn_) { + LOG(DEBUG, "TSN Agent mode : Enabled"); + } } void AgentParam::set_test_mode(bool mode) { @@ -868,12 +945,15 @@ void AgentParam::ParseArguments(int argc, char *argv[]) { AgentParam::AgentParam(Agent *agent, bool enable_flow_options, bool enable_vhost_options, bool enable_hypervisor_options, - bool enable_service_options) : + bool enable_service_options, + bool enable_tsn) : enable_flow_options_(enable_flow_options), enable_vhost_options_(enable_vhost_options), enable_hypervisor_options_(enable_hypervisor_options), enable_service_options_(enable_service_options), - vhost_(), eth_port_(), xmpp_instance_count_(), xmpp_server_1_(), + enable_tsn_(enable_tsn), vhost_(), agent_name_(), eth_port_(), + eth_port_no_arp_(false), eth_port_encap_type_(), + xmpp_instance_count_(), xmpp_server_1_(), xmpp_server_2_(), dns_server_1_(), dns_server_2_(), dns_port_1_(ContrailPorts::DnsServerPort()), dns_port_2_(ContrailPorts::DnsServerPort()), @@ -924,6 +1004,8 @@ AgentParam::AgentParam(Agent *agent, bool enable_flow_options, "Sandesh HTTP listener port") ("DEFAULT.tunnel_type", opt::value()->default_value("MPLSoGRE"), "Tunnel Encapsulation type ") + ("DEFAULT.tsn_mode", opt::value(), + "Run compute-node in TSN mode") ("DISCOVERY.server", opt::value(), "IP address of discovery server") ("DISCOVERY.max_control_nodes", opt::value(), @@ -1001,6 +1083,12 @@ AgentParam::AgentParam(Agent *agent, bool enable_flow_options, "Gateway IP address for virtual host") ("VIRTUAL-HOST-INTERFACE.physical_interface", opt::value(), "Physical interface name to which virtual host interface maps to") + ("VIRTUAL-HOST-INTERFACE.compute_node_address", + opt::value >()->multitoken(), + "List of addresses on compute node") + ("VIRTUAL-HOST-INTERFACE.physical_port_routes", + opt::value >()->multitoken(), + "Static routes to be added on physical interface") ; options_.add(vhost); } diff --git a/src/vnsw/agent/init/agent_param.h b/src/vnsw/agent/init/agent_param.h index e91160db21e..4cc6a8c298f 100644 --- a/src/vnsw/agent/init/agent_param.h +++ b/src/vnsw/agent/init/agent_param.h @@ -19,6 +19,7 @@ class AgentParam { static const uint32_t kAgentStatsInterval = (30 * 1000); // time in millisecs static const uint32_t kFlowStatsInterval = (1000); // time in milliseconds static const uint32_t kVrouterStatsInterval = (30 * 1000); //time-millisecs + typedef std::vector AddressList; // Hypervisor mode we are working on enum Mode { @@ -34,6 +35,7 @@ class AgentParam { VCENTER }; + struct PortInfo { PortInfo() : name_(""), vrf_(""), addr_(0), prefix_(0), plen_(0), gw_(0) {} @@ -50,7 +52,8 @@ class AgentParam { AgentParam(Agent *agent, bool enable_flow_options = true, bool enable_vhost_options = true, bool enable_hypervisor_options = true, - bool enable_service_options = true); + bool enable_service_options = true, + bool enable_tsn = false); virtual ~AgentParam(); virtual int Validate(); @@ -74,7 +77,10 @@ class AgentParam { const int xen_ll_plen() const { return xen_ll_.plen_; } const Ip4Address &xen_ll_gw() const { return xen_ll_.gw_; } + const std::string &agent_name() const { return agent_name_; } const std::string ð_port() const { return eth_port_; } + const bool ð_port_no_arp() const { return eth_port_no_arp_; } + const std::string ð_port_encap_type() const { return eth_port_encap_type_; } const Ip4Address &xmpp_server_1() const { return xmpp_server_1_; } const Ip4Address &xmpp_server_2() const { return xmpp_server_2_; } const Ip4Address &dns_server_1() const { return dns_server_1_; } @@ -154,6 +160,13 @@ class AgentParam { boost::program_options::options_description options() const { return options_; } + bool isTsnEnabled() const { return enable_tsn_; } + + const AddressList &compute_node_address_list() const { + return compute_node_address_list_; + } + void BuildAddressList(const std::string &val); + protected: void set_mode(Mode m) { mode_ = m; } virtual void InitFromSystem(); @@ -204,6 +217,7 @@ class AgentParam { void ParseHeadlessMode(); void ParseSimulateEvpnTor(); void ParseServiceInstance(); + void ParseTsnMode(); void ParseCollectorArguments (const boost::program_options::variables_map &v); @@ -225,6 +239,8 @@ class AgentParam { (const boost::program_options::variables_map &v); void ParseServiceInstanceArguments (const boost::program_options::variables_map &v); + void ParseTsnModeArguments + (const boost::program_options::variables_map &v); boost::program_options::variables_map var_map_; boost::program_options::options_description options_; @@ -232,9 +248,13 @@ class AgentParam { bool enable_vhost_options_; bool enable_hypervisor_options_; bool enable_service_options_; + bool enable_tsn_; PortInfo vhost_; + std::string agent_name_; std::string eth_port_; + bool eth_port_no_arp_; + std::string eth_port_encap_type_; uint16_t xmpp_instance_count_; Ip4Address xmpp_server_1_; Ip4Address xmpp_server_2_; @@ -253,7 +273,7 @@ class AgentParam { uint16_t linklocal_vm_flows_; uint16_t flow_cache_timeout_; - // Parameters configured from command linke arguments only (for now) + // Parameters configured from command line arguments only (for now) std::string config_file_; std::string program_name_; std::string log_file_; @@ -287,6 +307,8 @@ class AgentParam { int si_netns_timeout_; std::string si_haproxy_ssl_cert_path_; VmwareMode vmware_mode_; + // List of IP addresses on the compute node. + AddressList compute_node_address_list_; DISALLOW_COPY_AND_ASSIGN(AgentParam); }; diff --git a/src/vnsw/agent/init/contrail_init_common.cc b/src/vnsw/agent/init/contrail_init_common.cc index 612f535a150..c4587a79925 100644 --- a/src/vnsw/agent/init/contrail_init_common.cc +++ b/src/vnsw/agent/init/contrail_init_common.cc @@ -117,25 +117,63 @@ void ContrailInitCommon::CreateVrf() { } } +static PhysicalInterface::EncapType ComputeEncapType(const string &encap) { + if (encap == "none") { + return PhysicalInterface::RAW_IP; + } + return PhysicalInterface::ETHERNET; +} + +void ContrailInitCommon::ProcessComputeAddress(AgentParam *param) { + InetUnicastAgentRouteTable *rt_table = + agent()->fabric_inet4_unicast_table(); + + const AgentParam::AddressList &addr_list = + param->compute_node_address_list(); + AgentParam::AddressList::const_iterator it = addr_list.begin(); + while (it != addr_list.end()) { + rt_table->AddVHostRecvRouteReq(agent()->local_peer(), + agent()->fabric_vrf_name(), + param->vhost_name(), *it, 32, + agent()->fabric_vn_name(), false); + it++; + } + + // If compute_node_address are specified, it will mean user wants + // to run services such as metadata on an IP different than vhost. + // Set compute_node_ip_ to vhost_addr if no compute_node_address are + // specified. Else, pick first address to run in compute_node_address_list + // + // The compute_node_ip is used only in adding Flow NAT rules. + if (param->compute_node_address_list().size()) { + agent()->set_compute_node_ip(param->compute_node_address_list()[0]); + } +} + void ContrailInitCommon::CreateInterfaces() { InterfaceTable *table = agent()->interface_table(); + PhysicalInterface::EncapType type; + type = ComputeEncapType(agent_param()->eth_port_encap_type()); PhysicalInterface::Create(table, agent_param()->eth_port(), agent()->fabric_vrf_name(), - PhysicalInterface::FABRIC); + PhysicalInterface::FABRIC, type, + agent_param()->eth_port_no_arp()); + InetInterface::Create(table, agent_param()->vhost_name(), InetInterface::VHOST, agent()->fabric_vrf_name(), agent_param()->vhost_addr(), agent_param()->vhost_plen(), agent_param()->vhost_gw(), agent_param()->eth_port(), - agent()->fabric_vrf_name()); + agent()->fabric_vn_name()); agent()->InitXenLinkLocalIntf(); if (agent_param()->isVmwareMode()) { PhysicalInterface::Create(agent()->interface_table(), agent_param()->vmware_physical_port(), agent()->fabric_vrf_name(), - PhysicalInterface::VMWARE); + PhysicalInterface::VMWARE, + PhysicalInterface::ETHERNET, false); } InetInterfaceKey key(agent()->vhost_interface_name()); @@ -157,6 +195,8 @@ void ContrailInitCommon::CreateInterfaces() { if (agent()->vgw()) { agent()->vgw()->CreateInterfaces(); } + + ProcessComputeAddress(agent_param()); } void ContrailInitCommon::InitDone() { diff --git a/src/vnsw/agent/init/contrail_init_common.h b/src/vnsw/agent/init/contrail_init_common.h index e63d597b1ce..412e39a6668 100644 --- a/src/vnsw/agent/init/contrail_init_common.h +++ b/src/vnsw/agent/init/contrail_init_common.h @@ -20,6 +20,7 @@ class ContrailInitCommon : public AgentInit { void ProcessOptions(const std::string &config_file, const std::string &program_name); + void ProcessComputeAddress(AgentParam *param); int Start(); // Initialization virtual methods diff --git a/src/vnsw/agent/init/test/test_vmware.cc b/src/vnsw/agent/init/test/test_vmware.cc index 54deae8633e..746e2e64692 100644 --- a/src/vnsw/agent/init/test/test_vmware.cc +++ b/src/vnsw/agent/init/test/test_vmware.cc @@ -38,9 +38,9 @@ class VmwareTest : public ::testing::Test { AgentParam *param; Agent *agent; - int intf_count_; - int nh_count_; - int vrf_count_; + uint32_t intf_count_; + uint32_t nh_count_; + uint32_t vrf_count_; opt::options_description desc; opt::variables_map var_map; diff --git a/src/vnsw/agent/kstate/kstate.sandesh b/src/vnsw/agent/kstate/kstate.sandesh index a6bd62def53..38714ca1d50 100644 --- a/src/vnsw/agent/kstate/kstate.sandesh +++ b/src/vnsw/agent/kstate/kstate.sandesh @@ -195,11 +195,9 @@ struct KVrfStatsInfo { 10: i64 vrf_gre_mpls_tunnels; 11: i64 vrf_fabric_composites; 12: i64 vrf_l2_mcast_composites; - 13: i64 vrf_l3_mcast_composites; - 14: i64 vrf_multi_proto_composites; - 15: i64 vrf_ecmp_composites; - 16: i64 vrf_encaps; - 17: i64 vrf_vxlan_tunnels; + 13: i64 vrf_ecmp_composites; + 14: i64 vrf_encaps; + 15: i64 vrf_vxlan_tunnels; } request sandesh KVrfStatsReq { diff --git a/src/vnsw/agent/kstate/test/test_kstate.cc b/src/vnsw/agent/kstate/test/test_kstate.cc index dfc0b7c4d05..d55a4d997a7 100644 --- a/src/vnsw/agent/kstate/test/test_kstate.cc +++ b/src/vnsw/agent/kstate/test/test_kstate.cc @@ -91,13 +91,14 @@ class KStateTest : public ::testing::Test { void CreateVmPorts(struct PortInfo *input, int count) { CreateVmportEnv(input, count); } - void CreatePorts(int if_count, int nh_count, int rt_count, int num_ports = MAX_TEST_FD) { + void CreatePorts(uint32_t if_count, uint32_t nh_count, uint32_t rt_count, + uint32_t num_ports = MAX_TEST_FD) { int idx; client->Reset(); CreateVmPorts(input, num_ports); client->WaitForIdle(10); - for (int i = 0; i < num_ports; i++) { + for (uint32_t i = 0; i < num_ports; i++) { idx = i; WAIT_FOR(1000, 1000, (VmPortActive(input, idx) == true)); } @@ -113,10 +114,10 @@ class KStateTest : public ::testing::Test { Agent::GetInstance()->mpls_table()->Size())); if (!ksync_init_) { WAIT_FOR(1000, 1000, ((num_ports * 2) == - KSyncSockTypeMap::MplsCount())); + (uint32_t)KSyncSockTypeMap::MplsCount())); if (if_count) { WAIT_FOR(1000, 1000, ((num_ports + if_count) == - KSyncSockTypeMap::IfCount())); + (uint32_t)KSyncSockTypeMap::IfCount())); } if (nh_count) { //5 interface nexthops get created for each interface @@ -124,11 +125,11 @@ class KStateTest : public ::testing::Test { // without policy and 1 multicast - mac as all f's) //plus 4 Nexthops for each VRF (1 VRF NH and 2 Composite NHs) WAIT_FOR(1000, 1000, ((nh_count + (num_ports * 5) + 3) == - KSyncSockTypeMap::NHCount())); + (uint32_t)KSyncSockTypeMap::NHCount())); } if (rt_count) { WAIT_FOR(1000, 1000, ((rt_count + (num_ports * 2) + 1) == - KSyncSockTypeMap::RouteCount())); + (uint32_t)KSyncSockTypeMap::RouteCount())); } } } diff --git a/src/vnsw/agent/kstate/test/test_sandesh_kstate.cc b/src/vnsw/agent/kstate/test/test_sandesh_kstate.cc index 5df13be7d91..26e93efec2d 100644 --- a/src/vnsw/agent/kstate/test/test_sandesh_kstate.cc +++ b/src/vnsw/agent/kstate/test/test_sandesh_kstate.cc @@ -587,9 +587,9 @@ TEST_F(KStateSandeshTest, NhTest_flags) { KSyncSockTypeMap::NHAdd(212, flags); flags = NH_FLAG_VALID|NH_FLAG_COMPOSITE_L2; - KSyncSockTypeMap::NHAdd(215, flags); + KSyncSockTypeMap::NHAdd(213, flags); flags = NH_FLAG_COMPOSITE_L2; - KSyncSockTypeMap::NHAdd(216, flags); + KSyncSockTypeMap::NHAdd(214, flags); //Send NH DUMP request ClearCount(); @@ -618,10 +618,6 @@ TEST_F(KStateSandeshTest, NhTest_flags) { KSyncSockTypeMap::NHDelete(212); KSyncSockTypeMap::NHDelete(213); KSyncSockTypeMap::NHDelete(214); - KSyncSockTypeMap::NHDelete(215); - KSyncSockTypeMap::NHDelete(216); - KSyncSockTypeMap::NHDelete(217); - KSyncSockTypeMap::NHDelete(218); } TEST_F(KStateSandeshTest, NhTest_MultiResponse) { @@ -1029,11 +1025,7 @@ TEST_F(KStateSandeshTest, VrfStatsTest_MultiResponse) { ClearCount(); VrfStatsGet(-1); client->WaitForIdle(); - WAIT_FOR(1000, 1000, (response_count_ == 7)); - - //verify the response - EXPECT_EQ(7U, type_specific_response_count_); - EXPECT_EQ(100U, num_entries_); + WAIT_FOR(1000, 1000, (num_entries_ == 100U)); //cleanup for(int i = 1; i <= 100; i++) { diff --git a/src/vnsw/agent/ksync/interface_ksync.cc b/src/vnsw/agent/ksync/interface_ksync.cc index 42f0ae4c3e7..12ccc398c6e 100644 --- a/src/vnsw/agent/ksync/interface_ksync.cc +++ b/src/vnsw/agent/ksync/interface_ksync.cc @@ -58,13 +58,16 @@ InterfaceKSyncEntry::InterfaceKSyncEntry(InterfaceKSyncObject *obj, parent_(entry->parent_), policy_enabled_(entry->policy_enabled_), sub_type_(entry->sub_type_), + vm_sub_type_(entry->vm_sub_type_), type_(entry->type_), rx_vlan_id_(entry->rx_vlan_id_), tx_vlan_id_(entry->tx_vlan_id_), vrf_id_(entry->vrf_id_), persistent_(entry->persistent_), subtype_(entry->subtype_), - xconnect_(entry->xconnect_) { + xconnect_(entry->xconnect_), + no_arp_(entry->no_arp_), + encap_type_(entry->encap_type_) { } InterfaceKSyncEntry::InterfaceKSyncEntry(InterfaceKSyncObject *obj, @@ -90,13 +93,16 @@ InterfaceKSyncEntry::InterfaceKSyncEntry(InterfaceKSyncObject *obj, parent_(NULL), policy_enabled_(false), sub_type_(InetInterface::VHOST), + vm_sub_type_(VmInterface::NONE), type_(intf->type()), rx_vlan_id_(VmInterface::kInvalidVlanId), tx_vlan_id_(VmInterface::kInvalidVlanId), vrf_id_(intf->vrf_id()), persistent_(false), subtype_(PhysicalInterface::INVALID), - xconnect_(NULL) { + xconnect_(NULL), + no_arp_(false), + encap_type_(PhysicalInterface::ETHERNET) { if (intf->flow_key_nh()) { flow_key_nh_id_ = intf->flow_key_nh()->id(); @@ -115,6 +121,7 @@ InterfaceKSyncEntry::InterfaceKSyncEntry(InterfaceKSyncObject *obj, InterfaceKSyncEntry tmp(ksync_obj_, vmitf->parent()); parent_ = ksync_obj_->GetReference(&tmp); } + vm_sub_type_ = vmitf->sub_type(); } else if (type_ == Interface::INET) { const InetInterface *inet_intf = static_cast(intf); @@ -122,7 +129,16 @@ InterfaceKSyncEntry::InterfaceKSyncEntry(InterfaceKSyncObject *obj, if (sub_type_ == InetInterface::VHOST) { InterfaceKSyncEntry tmp(ksync_obj_, inet_intf->xconnect()); xconnect_ = ksync_obj_->GetReference(&tmp); + InterfaceKSyncEntry *xconnect = static_cast + (xconnect_.get()); + encap_type_ = xconnect->encap_type(); + no_arp_ = xconnect->no_arp(); } + } else if (type_ == Interface::PHYSICAL) { + const PhysicalInterface *physical_intf = + static_cast(intf); + encap_type_ = physical_intf->encap_type(); + no_arp_ = physical_intf->no_arp(); } } @@ -171,6 +187,11 @@ bool InterfaceKSyncEntry::Sync(DBEntry *e) { if (intf->type() == Interface::VM_INTERFACE) { VmInterface *vm_port = static_cast(intf); + if (vm_sub_type_ != vm_port->sub_type()) { + vm_sub_type_ = vm_port->sub_type(); + ret = true; + } + if (dhcp_enable_ != vm_port->dhcp_enable_config()) { dhcp_enable_ = vm_port->dhcp_enable_config(); ret = true; @@ -195,6 +216,16 @@ bool InterfaceKSyncEntry::Sync(DBEntry *e) { ret = true; } + if (rx_vlan_id_ != vm_port->rx_vlan_id()) { + rx_vlan_id_ = vm_port->rx_vlan_id(); + ret = true; + } + + if (tx_vlan_id_ != vm_port->tx_vlan_id()) { + tx_vlan_id_ = vm_port->tx_vlan_id(); + ret = true; + } + KSyncEntryPtr parent = NULL; if (vm_port->parent()) { InterfaceKSyncEntry tmp(ksync_obj_, vm_port->parent()); @@ -292,9 +323,29 @@ bool InterfaceKSyncEntry::Sync(DBEntry *e) { subtype_ = phy_intf->subtype(); break; } - case Interface::INET: + case Interface::INET: { dmac = intf->mac(); + + bool no_arp = false; + PhysicalInterface::EncapType encap = PhysicalInterface::ETHERNET; + InterfaceKSyncEntry *xconnect = static_cast + (xconnect_.get()); + if (xconnect) { + no_arp = xconnect->no_arp(); + encap = xconnect->encap_type(); + } + + if (no_arp_ != no_arp) { + no_arp_ = no_arp; + ret = true; + } + if (encap_type_ != encap) { + encap_type_ = encap; + ret = true; + } + break; + } default: assert(0); } @@ -348,9 +399,6 @@ KSyncEntry *InterfaceKSyncEntry::UnresolvedReference() { return NULL; } - if (rx_vlan_id_ == VmInterface::kInvalidVlanId) - return NULL; - if (parent_.get() && !parent_->IsResolved()) { return parent_.get(); } @@ -383,25 +431,37 @@ int InterfaceKSyncEntry::Encode(sandesh_op::type op, char *buf, int buf_len) { encoder.set_h_op(op); switch (type_) { case Interface::VM_INTERFACE: { + if (vm_sub_type_ == VmInterface::TOR) + return 0; if (dhcp_enable_) { flags |= VIF_FLAG_DHCP_ENABLED; } if (layer2_forwarding_) { flags |= VIF_FLAG_L2_ENABLED; } + if (vm_sub_type_ == VmInterface::VCPE) { + flags |= VIF_FLAG_NATIVE_VLAN_TAG; + } MacAddress mac; - if (rx_vlan_id_ == VmInterface::kInvalidVlanId) { - mac = ksync_obj_->ksync()->agent()->vrrp_mac(); - encoder.set_vifr_type(VIF_TYPE_VIRTUAL); - } else { + if (parent_.get() != NULL) { encoder.set_vifr_type(VIF_TYPE_VIRTUAL_VLAN); - encoder.set_vifr_vlan_id(rx_vlan_id_); - encoder.set_vifr_ovlan_id(tx_vlan_id_); + if (rx_vlan_id_ != VmInterface::kInvalidVlanId) { + encoder.set_vifr_vlan_id(rx_vlan_id_); + } else { + encoder.set_vifr_vlan_id(0); + } + if (tx_vlan_id_ != VmInterface::kInvalidVlanId) { + encoder.set_vifr_ovlan_id(tx_vlan_id_); + } else { + encoder.set_vifr_ovlan_id(0); + } InterfaceKSyncEntry *parent = (static_cast (parent_.get())); encoder.set_vifr_parent_vif_idx(parent->interface_id()); mac = parent->mac(); - + } else { + mac = ksync_obj_->ksync()->agent()->vrrp_mac(); + encoder.set_vifr_type(VIF_TYPE_VIRTUAL); } std::vector intf_mac((int8_t *)mac, (int8_t *)mac + mac.size()); @@ -418,6 +478,7 @@ int InterfaceKSyncEntry::Encode(sandesh_op::type op, char *buf, int buf_len) { case Interface::PHYSICAL: { encoder.set_vifr_type(VIF_TYPE_PHYSICAL); flags |= VIF_FLAG_L3_ENABLED; + flags |= VIF_FLAG_L2_ENABLED; if (!persistent_) { flags |= VIF_FLAG_VHOST_PHYS; } @@ -451,6 +512,7 @@ int InterfaceKSyncEntry::Encode(sandesh_op::type op, char *buf, int buf_len) { break; } flags |= VIF_FLAG_L3_ENABLED; + flags |= VIF_FLAG_L2_ENABLED; break; } diff --git a/src/vnsw/agent/ksync/interface_ksync.h b/src/vnsw/agent/ksync/interface_ksync.h index e4dc9caefbd..ae5a3485128 100644 --- a/src/vnsw/agent/ksync/interface_ksync.h +++ b/src/vnsw/agent/ksync/interface_ksync.h @@ -53,6 +53,8 @@ class InterfaceKSyncEntry : public KSyncNetlinkDBEntry { uint32_t interface_id() const {return interface_id_;} const string &interface_name() const {return interface_name_;} bool has_service_vlan() const {return has_service_vlan_;} + bool no_arp() const { return no_arp_; } + PhysicalInterface::EncapType encap_type() const { return encap_type_; } KSyncDBObject *GetObject(); virtual bool Sync(DBEntry *e); @@ -88,6 +90,7 @@ class InterfaceKSyncEntry : public KSyncNetlinkDBEntry { KSyncEntryPtr parent_; bool policy_enabled_; InetInterface::SubType sub_type_; + VmInterface::SubType vm_sub_type_; Interface::Type type_; uint16_t rx_vlan_id_; uint16_t tx_vlan_id_; @@ -95,6 +98,8 @@ class InterfaceKSyncEntry : public KSyncNetlinkDBEntry { bool persistent_; PhysicalInterface::SubType subtype_; KSyncEntryPtr xconnect_; + bool no_arp_; + PhysicalInterface::EncapType encap_type_; DISALLOW_COPY_AND_ASSIGN(InterfaceKSyncEntry); }; diff --git a/src/vnsw/agent/ksync/nexthop_ksync.cc b/src/vnsw/agent/ksync/nexthop_ksync.cc index f82b1524904..cf66377c20f 100644 --- a/src/vnsw/agent/ksync/nexthop_ksync.cc +++ b/src/vnsw/agent/ksync/nexthop_ksync.cc @@ -106,6 +106,12 @@ NHKSyncEntry::NHKSyncEntry(NHKSyncObject *obj, const NextHop *nh) : } case NextHop::RESOLVE: { + InterfaceKSyncObject *interface_object = + ksync_obj_->ksync()->interface_ksync_obj(); + const ResolveNH *rsl_nh = static_cast(nh); + InterfaceKSyncEntry if_ksync(interface_object, rsl_nh->interface()); + interface_ = interface_object->GetReference(&if_ksync); + vrf_id_ = rsl_nh->interface()->vrf_id(); break; } @@ -185,10 +191,18 @@ bool NHKSyncEntry::IsLess(const KSyncEntry &rhs) const { return type_ < entry.type_; } - if (type_ == NextHop::DISCARD || type_ == NextHop::RESOLVE) { + if (type_ == NextHop::DISCARD) { return false; } + if (type_ == NextHop::ARP) { + //Policy is ignored for ARP NH + if (vrf_id_ != entry.vrf_id_) { + return vrf_id_ < entry.vrf_id_; + } + return sip_.s_addr < entry.sip_.s_addr; + } + if (policy_ != entry.policy_) { return policy_ < entry.policy_; } @@ -197,13 +211,6 @@ bool NHKSyncEntry::IsLess(const KSyncEntry &rhs) const { return vrf_id_ < entry.vrf_id_; } - if (type_ == NextHop::ARP) { - if (vrf_id_ != entry.vrf_id_) { - return vrf_id_ < entry.vrf_id_; - } - return sip_.s_addr < entry.sip_.s_addr; - } - if (type_ == NextHop::INTERFACE) { if (is_mcast_nh_ != entry.is_mcast_nh_) { return is_mcast_nh_ < entry.is_mcast_nh_; @@ -214,10 +221,11 @@ bool NHKSyncEntry::IsLess(const KSyncEntry &rhs) const { return interface() < entry.interface(); } - if (type_ == NextHop::RECEIVE) { + if (type_ == NextHop::RECEIVE || type_ == NextHop::RESOLVE) { return interface() < entry.interface(); } + if (type_ == NextHop::TUNNEL) { if (vrf_id_ != entry.vrf_id_) { return vrf_id_ < entry.vrf_id_; @@ -451,18 +459,21 @@ bool NHKSyncEntry::Sync(DBEntry *e) { const TunnelNH *tun_nh = static_cast(e); const NextHop *active_nh = tun_nh->GetRt()->GetActiveNextHop(); - if (active_nh->GetType() != NextHop::ARP) { - valid_ = false; - interface_ = NULL; - dmac_.Zero(); - break; + if (active_nh->GetType() == NextHop::ARP) { + const ArpNH *arp_nh = static_cast(active_nh); + InterfaceKSyncObject *interface_object = + ksync_obj_->ksync()->interface_ksync_obj(); + InterfaceKSyncEntry if_ksync(interface_object, arp_nh->GetInterface()); + interface_ = interface_object->GetReference(&if_ksync); + dmac_ = arp_nh->GetMac(); + } else if (active_nh->GetType() == NextHop::INTERFACE) { + const InterfaceNH *intf_nh = + static_cast(active_nh); + InterfaceKSyncObject *interface_object = + ksync_obj_->ksync()->interface_ksync_obj(); + InterfaceKSyncEntry if_ksync(interface_object, intf_nh->GetInterface()); + interface_ = interface_object->GetReference(&if_ksync); } - const ArpNH *arp_nh = static_cast(active_nh); - InterfaceKSyncObject *interface_object = - ksync_obj_->ksync()->interface_ksync_obj(); - InterfaceKSyncEntry if_ksync(interface_object, arp_nh->GetInterface()); - interface_ = interface_object->GetReference(&if_ksync); - dmac_ = arp_nh->GetMac(); break; } @@ -622,7 +633,7 @@ int NHKSyncEntry::Encode(sandesh_op::type op, char *buf, int buf_len) { } encoder.set_nhr_encap_oif_id(intf_id); - SetEncap(NULL,encap); + SetEncap(if_ksync,encap); encoder.set_nhr_encap(encap); if (tunnel_type_.GetType() == TunnelType::MPLS_UDP) { flags |= NH_FLAG_TUNNEL_UDP_MPLS; @@ -950,6 +961,10 @@ void NHKSyncEntry::SetEncap(InterfaceKSyncEntry *if_ksync, return; } + if (if_ksync && if_ksync->encap_type() == PhysicalInterface::RAW_IP) { + return; + } + const MacAddress *smac = &MacAddress::ZeroMac(); /* DMAC encode */ for (size_t i = 0 ; i < dmac_.size(); i++) { diff --git a/src/vnsw/agent/ksync/route_ksync.cc b/src/vnsw/agent/ksync/route_ksync.cc index 658324c3dd2..4f09946a64d 100644 --- a/src/vnsw/agent/ksync/route_ksync.cc +++ b/src/vnsw/agent/ksync/route_ksync.cc @@ -14,6 +14,7 @@ #include #include +#include "cmn/agent.h" #include "oper/interface_common.h" #include "oper/nexthop.h" #include "oper/route_common.h" @@ -48,7 +49,8 @@ RouteKSyncEntry::RouteKSyncEntry(RouteKSyncObject* obj, const AgentRoute *rt) : vrf_id_(rt->vrf_id()), nh_(NULL), label_(0), proxy_arp_(false), tunnel_type_(TunnelType::DefaultType()), wait_for_traffic_(false) { boost::system::error_code ec; - switch (rt->GetTableType()) { + rt_type_ = rt->GetTableType(); + switch (rt_type_) { case Agent::INET4_UNICAST: { const InetUnicastRouteEntry *uc_rt = static_cast(rt); @@ -77,7 +79,6 @@ RouteKSyncEntry::RouteKSyncEntry(RouteKSyncObject* obj, const AgentRoute *rt) : const Layer2RouteEntry *l2_rt = static_cast(rt); mac_ = l2_rt->GetAddress(); - rt_type_ = RT_LAYER2; prefix_len_ = 0; break; } @@ -139,7 +140,13 @@ bool RouteKSyncEntry::IsLess(const KSyncEntry &rhs) const { if (rt_type_ != entry.rt_type_) return rt_type_ < entry.rt_type_; - if (rt_type_ == RT_LAYER2) { + //First unicast + if ((rt_type_ == Agent::INET4_UNICAST) || + (rt_type_ == Agent::INET6_UNICAST)) { + return UcIsLess(rhs); + } + + if (rt_type_ == Agent::LAYER2) { return L2IsLess(rhs); } @@ -195,7 +202,7 @@ bool RouteKSyncEntry::Sync(DBEntry *e) { } //Bother for label for unicast and EVPN routes - if (rt_type_ == RT_LAYER2) { + if (rt_type_ != Agent::INET4_MULTICAST) { uint32_t old_label = label_; const AgentPath *path = (static_cast (e))->GetActivePath(); @@ -253,21 +260,17 @@ int RouteKSyncEntry::Encode(sandesh_op::type op, uint8_t replace_plen, encoder.set_h_op(op); encoder.set_rtr_rid(0); encoder.set_rtr_vrf_id(vrf_id_); - if (rt_type_ != RT_LAYER2) { + if (rt_type_ != Agent::LAYER2) { if (addr_.is_v4()) { encoder.set_rtr_family(AF_INET); boost::array bytes = addr_.to_v4().to_bytes(); std::vector rtr_prefix(bytes.begin(), bytes.end()); encoder.set_rtr_prefix(rtr_prefix); - boost::array src_bytes = src_addr_.to_v4().to_bytes(); - std::vector rtr_src(src_bytes.begin(), src_bytes.end()); } else if (addr_.is_v6()) { encoder.set_rtr_family(AF_INET6); boost::array bytes = addr_.to_v6().to_bytes(); std::vector rtr_prefix(bytes.begin(), bytes.end()); encoder.set_rtr_prefix(rtr_prefix); - boost::array src_bytes = src_addr_.to_v6().to_bytes(); - std::vector rtr_src(src_bytes.begin(), src_bytes.end()); } encoder.set_rtr_prefix_len(prefix_len_); } else { @@ -280,14 +283,14 @@ int RouteKSyncEntry::Encode(sandesh_op::type op, uint8_t replace_plen, int label = 0; int flags = 0; - if (rt_type_ == RT_LAYER2) { + if (rt_type_ != Agent::INET4_MULTICAST) { if (nexthop != NULL && nexthop->type() == NextHop::TUNNEL) { label = label_; flags |= VR_RT_LABEL_VALID_FLAG; } } - if (rt_type_ == RT_LAYER2) { + if (rt_type_ == Agent::LAYER2) { flags |= 0x02; label = label_; if (nexthop != NULL && nexthop->type() == NextHop::COMPOSITE) { @@ -341,8 +344,9 @@ int RouteKSyncEntry::DeleteMsg(char *buf, int buf_len) { RouteKSyncEntry *route = NULL; NHKSyncEntry *ksync_nh = NULL; - // IF EVPN delete unconditionally - if (rt_type_ == RT_LAYER2) { + // IF multicast or EVPN delete unconditionally + if ((rt_type_ == Agent::LAYER2) || + (rt_type_ == Agent::INET4_MULTICAST)) { return DeleteInternal(nh(), 0, 0, false, buf, buf_len); } diff --git a/src/vnsw/agent/ksync/route_ksync.h b/src/vnsw/agent/ksync/route_ksync.h index 535bf68bd7d..0ffcdcbba1d 100644 --- a/src/vnsw/agent/ksync/route_ksync.h +++ b/src/vnsw/agent/ksync/route_ksync.h @@ -20,8 +20,6 @@ #include "ksync/agent_ksync_types.h" #include "ksync/nexthop_ksync.h" -#define RT_LAYER2 2 - class RouteKSyncObject; class RouteKSyncEntry : public KSyncNetlinkDBEntry { @@ -58,7 +56,7 @@ class RouteKSyncEntry : public KSyncNetlinkDBEntry { bool McIsLess(const KSyncEntry &rhs) const; bool L2IsLess(const KSyncEntry &rhs) const; RouteKSyncObject* ksync_obj_; - uint32_t rt_type_; + Agent::RouteTableType rt_type_; uint32_t vrf_id_; IpAddress addr_; IpAddress src_addr_; diff --git a/src/vnsw/agent/ksync/vnswif_listener_base.cc b/src/vnsw/agent/ksync/vnswif_listener_base.cc index f90a08454b8..159b2ecaf76 100644 --- a/src/vnsw/agent/ksync/vnswif_listener_base.cc +++ b/src/vnsw/agent/ksync/vnswif_listener_base.cc @@ -334,7 +334,8 @@ void VnswInterfaceListenerBase::HandleAddressEvent(const Event *event) { agent_->set_vhost_prefix_len(event->plen_); InetInterface::CreateReq(agent_->interface_table(), agent_->vhost_interface_name(), - InetInterface::VHOST, agent_->fabric_vrf_name(), + InetInterface::VHOST, + agent_->fabric_vrf_name(), event->addr_, event->plen_, agent_->vhost_default_gateway(), Agent::NullString(), agent_->fabric_vrf_name()); diff --git a/src/vnsw/agent/openstack/instance_service_server.cc b/src/vnsw/agent/openstack/instance_service_server.cc index fcb564aa681..4d589dcac39 100644 --- a/src/vnsw/agent/openstack/instance_service_server.cc +++ b/src/vnsw/agent/openstack/instance_service_server.cc @@ -36,7 +36,7 @@ InstanceServiceAsyncHandler::InstanceServiceAsyncHandler(Agent *agent) : io_service_(*(agent->event_manager()->io_service())), agent_(agent), version_(0), vgw_version_(0), - novaPeer_(new Peer(Peer::NOVA_PEER, NOVA_PEER_NAME)), + novaPeer_(new Peer(Peer::NOVA_PEER, NOVA_PEER_NAME, false)), interface_stale_cleaner_(new InterfaceConfigStaleCleaner(agent)), vgw_stale_cleaner_(new ConfigStaleCleaner(agent, boost::bind( &InstanceServiceAsyncHandler::OnVirtualGatewayStaleTimeout, this, _1))) { diff --git a/src/vnsw/agent/oper/agent.sandesh b/src/vnsw/agent/oper/agent.sandesh index 29a5639cbac..8127fb4d692 100644 --- a/src/vnsw/agent/oper/agent.sandesh +++ b/src/vnsw/agent/oper/agent.sandesh @@ -69,6 +69,8 @@ struct ItfSandeshData { 37: i16 tx_vlan_id; 38: i16 rx_vlan_id; 39: string parent_interface; + 40: optional string subnet; + 41: optional string sub_type; } struct VnIpamData { @@ -77,6 +79,7 @@ struct VnIpamData { 3: string gateway; 4: string ipam_name; 5: string dhcp_enable; + 6: string dns_server; } struct VnIpamHostRoutes { @@ -96,6 +99,7 @@ struct VnSandeshData { 9: bool layer2_forwarding; 10: bool ipv4_forwarding; 11: bool admin_state; + 12: i32 table_label; } struct SgSandeshData { @@ -811,6 +815,8 @@ struct VnObjectLogIpam { 2: i32 prefix_len; 3: optional string gateway_ip; 4: string ipam_name; + 5: string dhcp_enable; + 6: string dns_server; } struct VnObjectLogInfo { diff --git a/src/vnsw/agent/oper/agent_path.cc b/src/vnsw/agent/oper/agent_path.cc index ebcb5f3ac94..cc21c74f82d 100644 --- a/src/vnsw/agent/oper/agent_path.cc +++ b/src/vnsw/agent/oper/agent_path.cc @@ -43,7 +43,7 @@ AgentPath::~AgentPath() { } uint32_t AgentPath::GetTunnelBmap() const { - TunnelType::Type type = TunnelType::ComputeType(TunnelType::AllType()); + TunnelType::Type type = TunnelType::ComputeType(tunnel_bmap_); if ((type == (1 << TunnelType::VXLAN)) && (vxlan_id_ != 0)) { return (1 << TunnelType::VXLAN); } else { @@ -80,15 +80,29 @@ const NextHop* AgentPath::nexthop(Agent *agent) const { bool AgentPath::ChangeNH(Agent *agent, NextHop *nh) { // If NH is not found, point route to discard NH + bool ret = false; if (nh == NULL) { nh = agent->nexthop_table()->discard_nh(); } if (nh_ != nh) { nh_ = nh; - return true; + ret = true; } - return false; + + if (peer_ && (peer_->GetType() == Peer::MULTICAST_PEER) && + (label_ != MplsTable::kInvalidLabel)) { + MplsLabelKey key(MplsLabel::MCAST_NH, label_); + MplsLabel *mpls = static_cast(agent->mpls_table()-> + FindActiveEntry(&key)); + ret = agent->mpls_table()->ChangeNH(mpls, nh); + if (mpls) { + //Send notify of change + mpls->get_table_partition()->Notify(mpls); + } + } + + return ret; } bool AgentPath::RebakeAllTunnelNHinCompositeNH(const AgentRoute *sync_route) { @@ -167,7 +181,10 @@ bool AgentPath::UpdateNHPolicy(Agent *agent) { } bool AgentPath::UpdateTunnelType(Agent *agent, const AgentRoute *sync_route) { - if (tunnel_type_ == TunnelType::ComputeType(tunnel_bmap_)) { + //Return if there is no change in tunnel type for non Composite NH. + //For composite NH component needs to be traversed. + if ((tunnel_type_ == TunnelType::ComputeType(tunnel_bmap_)) && + (nh_.get() && nh_.get()->GetType() != NextHop::COMPOSITE)) { return false; } @@ -244,7 +261,11 @@ bool AgentPath::Sync(AgentRoute *sync_route) { if (rt == NULL || rt->plen() == 0) { unresolved = true; } else if (rt->GetActiveNextHop()->GetType() == NextHop::RESOLVE) { - table->AddArpReq(vrf_name_, gw_ip_); + const ResolveNH *nh = + static_cast(rt->GetActiveNextHop()); + table->AddArpReq(vrf_name_, gw_ip_, nh->interface()->vrf()->GetName(), + nh->interface(), nh->PolicyEnabled(), dest_vn_name_, + sg_list_); unresolved = true; } else { unresolved = false; @@ -278,7 +299,8 @@ bool AgentPath::IsLess(const AgentPath &r_path) const { return peer()->IsLess(r_path.peer()); } -bool HostRoute::AddChangePath(Agent *agent, AgentPath *path) { +bool HostRoute::AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt) { bool ret = false; NextHop *nh = NULL; InterfaceNHKey key(intf_.Clone(), false, InterfaceNHFlags::INET4); @@ -300,7 +322,8 @@ bool HostRoute::AddChangePath(Agent *agent, AgentPath *path) { return ret; } -bool InetInterfaceRoute::AddChangePath(Agent *agent, AgentPath *path) { +bool InetInterfaceRoute::AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt) { bool ret = false; NextHop *nh = NULL; InterfaceNHKey key(intf_.Clone(), false, InterfaceNHFlags::INET4); @@ -329,7 +352,8 @@ bool InetInterfaceRoute::AddChangePath(Agent *agent, AgentPath *path) { return ret; } -bool DropRoute::AddChangePath(Agent *agent, AgentPath *path) { +bool DropRoute::AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt) { bool ret = false; if (path->dest_vn_name() != vn_) { @@ -346,7 +370,8 @@ bool DropRoute::AddChangePath(Agent *agent, AgentPath *path) { return ret; } -bool LocalVmRoute::AddChangePath(Agent *agent, AgentPath *path) { +bool LocalVmRoute::AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt) { bool ret = false; NextHop *nh = NULL; SecurityGroupList path_sg_list; @@ -455,7 +480,8 @@ bool LocalVmRoute::AddChangePath(Agent *agent, AgentPath *path) { return ret; } -bool VlanNhRoute::AddChangePath(Agent *agent, AgentPath *path) { +bool VlanNhRoute::AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt) { bool ret = false; NextHop *nh = NULL; SecurityGroupList path_sg_list; @@ -506,24 +532,38 @@ bool VlanNhRoute::AddChangePath(Agent *agent, AgentPath *path) { return ret; } -bool ResolveRoute::AddChangePath(Agent *agent, AgentPath *path) { +bool ResolveRoute::AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt) { bool ret = false; NextHop *nh = NULL; - ResolveNHKey key; + ResolveNHKey key(intf_key_.get(), policy_); nh = static_cast(agent->nexthop_table()->FindActiveEntry(&key)); path->set_unresolved(false); - if (path->dest_vn_name() != agent->fabric_vn_name()) { - path->set_dest_vn_name(agent->fabric_vn_name()); + + if (path->dest_vn_name() != dest_vn_name_) { + path->set_dest_vn_name(dest_vn_name_); ret = true; } + + if (path->label() != label_) { + path->set_label(label_); + ret = true; + } + + if (path->sg_list() != path_sg_list_) { + path->set_sg_list(path_sg_list_); + ret = true; + } + if (path->ChangeNH(agent, nh) == true) ret = true; return ret; } -bool ReceiveRoute::AddChangePath(Agent *agent, AgentPath *path) { +bool ReceiveRoute::AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt) { bool ret = false; NextHop *nh = NULL; @@ -553,7 +593,8 @@ bool ReceiveRoute::AddChangePath(Agent *agent, AgentPath *path) { return ret; } -bool MulticastRoute::AddChangePath(Agent *agent, AgentPath *path) { +bool MulticastRoute::AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt) { bool ret = false; bool is_subnet_discard = false; NextHop *nh = NULL; @@ -617,7 +658,8 @@ bool MulticastRoute::CopyPathParameters(Agent *agent, return true; } -bool PathPreferenceData::AddChangePath(Agent *agent, AgentPath *path) { +bool PathPreferenceData::AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt) { bool ret = false; //ECMP flag will not be changed by path preference module, //hence retain value in path @@ -881,3 +923,11 @@ bool AgentPath::ChangeCompositeNH(Agent *agent, } return false; } + +const Ip4Address *AgentPath::NexthopIp(Agent *agent) const { + if (peer_ == NULL) { + return agent->router_ip_ptr(); + } + + return peer_->NexthopIp(agent, this); +} diff --git a/src/vnsw/agent/oper/agent_path.h b/src/vnsw/agent/oper/agent_path.h index 4043f3dd1ab..1c6d9d70d50 100644 --- a/src/vnsw/agent/oper/agent_path.h +++ b/src/vnsw/agent/oper/agent_path.h @@ -15,6 +15,8 @@ //Forward declaration class AgentXmppChannel; +class InterfaceKey; +class PhysicalInterface; class Peer; class PathPreference { @@ -91,7 +93,7 @@ struct PathPreferenceData : public AgentRouteData { virtual std::string ToString() const { return ""; } - virtual bool AddChangePath(Agent*, AgentPath*); + virtual bool AddChangePath(Agent*, AgentPath*, const AgentRoute*); PathPreference path_preference_; }; @@ -133,7 +135,7 @@ class AgentPath : public Path { void set_vrf_name(const std::string &vrf_name) {vrf_name_ = vrf_name;} void set_tunnel_bmap(TunnelType::TypeBmap bmap) {tunnel_bmap_ = bmap;} void set_tunnel_type(TunnelType::Type type) {tunnel_type_ = type;} - void set_sg_list(SecurityGroupList &sg) {sg_list_ = sg;} + void set_sg_list(const SecurityGroupList &sg) {sg_list_ = sg;} void clear_sg_list() { sg_list_.clear(); } void set_server_ip(const Ip4Address &server_ip) {server_ip_ = server_ip;} void set_is_subnet_discard(bool discard) { @@ -170,6 +172,8 @@ class AgentPath : public Path { } bool ReorderCompositeNH(Agent *agent, CompositeNHKey *nh); bool ChangeCompositeNH(Agent *agent, CompositeNHKey *nh); + // Get nexthop-ip address to be used for path + const Ip4Address *NexthopIp(Agent *agent) const; private: const Peer *peer_; // Nexthop for route. Not used for gateway routes @@ -228,11 +232,20 @@ class AgentPath : public Path { class ResolveRoute : public AgentRouteData { public: - ResolveRoute() : AgentRouteData(false) { } + ResolveRoute(const InterfaceKey *key, bool policy, const uint32_t label, + const string &vn_name, const SecurityGroupList &sg_list) : + AgentRouteData(false), intf_key_(key->Clone()), policy_(policy), + label_(label), dest_vn_name_(vn_name), path_sg_list_(sg_list) {} virtual ~ResolveRoute() { } - virtual bool AddChangePath(Agent *agent, AgentPath *path); + virtual bool AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt); virtual std::string ToString() const {return "Resolve";} private: + boost::scoped_ptr intf_key_; + bool policy_; + uint32_t label_; + const std::string dest_vn_name_; + const SecurityGroupList path_sg_list_; DISALLOW_COPY_AND_ASSIGN(ResolveRoute); }; @@ -252,7 +265,8 @@ class LocalVmRoute : public AgentRouteData { virtual ~LocalVmRoute() { } void DisableProxyArp() {proxy_arp_ = false;} virtual std::string ToString() const {return "local VM";} - virtual bool AddChangePath(Agent *agent, AgentPath *path); + virtual bool AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt); const SecurityGroupList &sg_list() const {return sg_list_;} void set_tunnel_bmap(TunnelType::TypeBmap bmap) {tunnel_bmap_ = bmap;} const PathPreference& path_preference() const { return path_preference_;} @@ -286,7 +300,8 @@ class InetInterfaceRoute : public AgentRouteData { tunnel_bmap_(tunnel_bmap), dest_vn_name_(dest_vn_name) { } virtual ~InetInterfaceRoute() { } - virtual bool AddChangePath(Agent *agent, AgentPath *path); + virtual bool AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt); virtual std::string ToString() const {return "host";} private: @@ -305,7 +320,8 @@ class HostRoute : public AgentRouteData { } virtual ~HostRoute() { } void EnableProxyArp() {proxy_arp_ = true;} - virtual bool AddChangePath(Agent *agent, AgentPath *path); + virtual bool AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt); virtual std::string ToString() const {return "host";} private: @@ -325,7 +341,8 @@ class VlanNhRoute : public AgentRouteData { path_preference_(path_preference), tunnel_bmap_(TunnelType::MplsType()) { } virtual ~VlanNhRoute() { } - virtual bool AddChangePath(Agent *agent, AgentPath *path); + virtual bool AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt); virtual std::string ToString() const {return "vlannh";} private: @@ -349,7 +366,8 @@ class MulticastRoute : public AgentRouteData { composite_nh_req_.Swap(&nh_req); } virtual ~MulticastRoute() { } - virtual bool AddChangePath(Agent *agent, AgentPath *path); + virtual bool AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt); virtual std::string ToString() const {return "multicast";} static bool CopyPathParameters(Agent *agent, AgentPath *path, @@ -390,7 +408,8 @@ class ReceiveRoute : public AgentRouteData { } virtual ~ReceiveRoute() { } void EnableProxyArp() {proxy_arp_ = true;} - virtual bool AddChangePath(Agent *agent, AgentPath *path); + virtual bool AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt); virtual std::string ToString() const {return "receive";} private: @@ -407,32 +426,45 @@ class ReceiveRoute : public AgentRouteData { class Inet4UnicastArpRoute : public AgentRouteData { public: Inet4UnicastArpRoute(const std::string &vrf_name, - const Ip4Address &addr) : - AgentRouteData(false), vrf_name_(vrf_name), addr_(addr) { + const Ip4Address &addr, bool policy, + const std::string &vn, const SecurityGroupList &sg) : + AgentRouteData(false), vrf_name_(vrf_name), addr_(addr), + policy_(policy), vn_(vn), sg_list_(sg) { } virtual ~Inet4UnicastArpRoute() { } - virtual bool AddChangePath(Agent *agent, AgentPath *path); + virtual bool AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt); virtual std::string ToString() const {return "arp";} private: std::string vrf_name_; Ip4Address addr_; + bool policy_; + std::string vn_; + SecurityGroupList sg_list_; DISALLOW_COPY_AND_ASSIGN(Inet4UnicastArpRoute); }; class Inet4UnicastGatewayRoute : public AgentRouteData { public: Inet4UnicastGatewayRoute(const Ip4Address &gw_ip, - const std::string &vrf_name) : - AgentRouteData(false), gw_ip_(gw_ip), vrf_name_(vrf_name) { + const std::string &vrf_name, + const std::string &vn_name, + uint32_t label, const SecurityGroupList &sg) : + AgentRouteData(false), gw_ip_(gw_ip), vrf_name_(vrf_name), + vn_name_(vn_name), mpls_label_(label), sg_list_(sg) { } virtual ~Inet4UnicastGatewayRoute() { } - virtual bool AddChangePath(Agent *agent, AgentPath *path); + virtual bool AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt); virtual std::string ToString() const {return "gateway";} private: Ip4Address gw_ip_; std::string vrf_name_; + std::string vn_name_; + uint32_t mpls_label_; + const SecurityGroupList sg_list_; DISALLOW_COPY_AND_ASSIGN(Inet4UnicastGatewayRoute); }; @@ -441,10 +473,28 @@ class DropRoute : public AgentRouteData { DropRoute(const string &vn_name) : AgentRouteData(false), vn_(vn_name) { } virtual ~DropRoute() { } - virtual bool AddChangePath(Agent *agent, AgentPath *path); + virtual bool AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt); virtual std::string ToString() const {return "drop";} private: std::string vn_; DISALLOW_COPY_AND_ASSIGN(DropRoute); }; + +class Inet4UnicastInterfaceRoute : public AgentRouteData { +public: + Inet4UnicastInterfaceRoute(const PhysicalInterface *interface, + const std::string &vn_name); + virtual ~Inet4UnicastInterfaceRoute() { } + + virtual bool AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt); + virtual std::string ToString() const {return "Interface";} + +private: + std::auto_ptr interface_key_; + std::string vn_name_; + DISALLOW_COPY_AND_ASSIGN(Inet4UnicastInterfaceRoute); +}; + #endif // vnsw_agent_path_hpp diff --git a/src/vnsw/agent/oper/agent_route.cc b/src/vnsw/agent/oper/agent_route.cc index ea1149c23db..d2cc6c7f3eb 100644 --- a/src/vnsw/agent/oper/agent_route.cc +++ b/src/vnsw/agent/oper/agent_route.cc @@ -324,7 +324,7 @@ void AgentRouteTable::Input(DBTablePartition *part, DBClient *client, //wait for traffic flag for a path path = rt->FindPath(key->peer()); if (path) { - notify = data->AddChangePath(agent_, path); + notify = data->AddChangePath(agent_, path, rt); } } else { //Ignore RESYNC if received on non-existing @@ -369,7 +369,7 @@ void AgentRouteTable::Input(DBTablePartition *part, DBClient *client, if (path == NULL) { path = new AgentPath(key->peer(), rt); rt->InsertPath(path); - data->AddChangePath(agent_, path); + data->AddChangePath(agent_, path, rt); notify = true; RouteInfo rt_info; @@ -379,7 +379,7 @@ void AgentRouteTable::Input(DBTablePartition *part, DBClient *client, // Let path know of route change and update itself path->set_is_stale(false); bool ecmp = path->path_preference().ecmp(); - notify = data->AddChangePath(agent_, path); + notify = data->AddChangePath(agent_, path, rt); //If a path transition from ECMP to non ECMP //remote the path from ecmp peer if (ecmp && ecmp != path->path_preference().ecmp()) { @@ -523,9 +523,15 @@ AgentPath *AgentRoute::FindLocalVmPortPath() const { if (path->peer() == NULL) { continue; } + if (path->peer()->export_to_controller()) { + return const_cast(path); + } + if (path->peer()->GetType() == Peer::ECMP_PEER || path->peer()->GetType() == Peer::VGW_PEER || - path->peer()->GetType() == Peer::LOCAL_VM_PORT_PEER) { + path->peer()->GetType() == Peer::LOCAL_VM_PORT_PEER || + path->peer()->GetType() == Peer::MULTICAST_TOR_PEER || + path->peer()->GetType() == Peer::OVS_PEER) { return const_cast(path); } } @@ -698,3 +704,210 @@ void AgentRouteTable::StalePathFromPeer(DBTablePartBase *part, AgentRoute *rt, part->Notify(rt); } } + +bool AgentRoute::ReComputeMulticastPaths(AgentPath *path, bool del) { + if (path->peer() == NULL) { + return false; + } + + //HACK: subnet route uses multicast NH. During IPAM delete + //subnet discard is deleted. Consider this as delete of all + //paths. Though this can be handled via multicast module + //which can also issue delete of all peers, however + //this is a temporary code as subnet route will not use + //multicast NH. + bool delete_all = false; + if (path->is_subnet_discard() && del) { + delete_all = true; + } + + Agent *agent = + (static_cast (get_table()))->agent(); + std::vector delete_paths; + if (del && (path->peer() == agent->multicast_peer())) + return false; + + //Possible paths: + //EVPN path - can be from multiple peers. + //Fabric path - from multicast builder + //Multicast peer + AgentPath *multicast_peer_path = NULL; + AgentPath *local_peer_path = NULL; + AgentPath *evpn_peer_path = NULL; + AgentPath *fabric_peer_path = NULL; + AgentPath *tor_peer_path = NULL; + + //Delete path label + if (del) { + MplsLabel::DeleteReq(path->label()); + } + + for (Route::PathList::iterator it = GetPathList().begin(); + it != GetPathList().end(); it++) { + AgentPath *it_path = + static_cast(it.operator->()); + + if (delete_all && (it_path->peer() != agent->multicast_peer())) + continue; + + //Handle deletions + if (del && (path->peer() == it_path->peer())) { + continue; + } + + //Handle Add/Changes + if (it_path->peer() == agent->local_vm_peer()) { + local_peer_path = it_path; + } else if (it_path->peer()->GetType() == Peer::MULTICAST_TOR_PEER) { + tor_peer_path = it_path; + } else if (it_path->peer()->GetType() == Peer::BGP_PEER) { + //Pick up the first peer. + if (evpn_peer_path == NULL) + evpn_peer_path = it_path; + } else if (it_path->peer()->GetType() == + Peer::MULTICAST_FABRIC_TREE_BUILDER) { + fabric_peer_path = it_path; + } else if (it_path->peer() == agent->multicast_peer()) { + multicast_peer_path = it_path; + } + } + + //all paths are gone so delete multicast_peer path as well + if ((local_peer_path == NULL) && + (tor_peer_path == NULL) && + (evpn_peer_path == NULL) && + (fabric_peer_path == NULL)) { + if (multicast_peer_path != NULL) + RemovePath(multicast_peer_path); + return true; + } + + uint32_t old_fabric_mpls_label = 0; + if (multicast_peer_path == NULL) { + multicast_peer_path = new AgentPath(agent->multicast_peer(), NULL); + InsertPath(multicast_peer_path); + } else { + old_fabric_mpls_label = multicast_peer_path->label(); + } + + ComponentNHKeyList component_nh_list; + + if (tor_peer_path) { + NextHopKey *tor_peer_key = + static_cast((tor_peer_path-> + nexthop(agent)->GetDBRequestKey()).release()); + std::auto_ptr key4(tor_peer_key); + ComponentNHKeyPtr component_nh_data4(new ComponentNHKey(0, key4)); + component_nh_list.push_back(component_nh_data4); + } + + if (evpn_peer_path) { + NextHopKey *evpn_peer_key = + static_cast((evpn_peer_path-> + nexthop(agent)->GetDBRequestKey()).release()); + std::auto_ptr key2(evpn_peer_key); + ComponentNHKeyPtr component_nh_data2(new ComponentNHKey(0, key2)); + component_nh_list.push_back(component_nh_data2); + } + + if (fabric_peer_path) { + NextHopKey *fabric_peer_key = + static_cast((fabric_peer_path-> + nexthop(agent)->GetDBRequestKey()).release()); + std::auto_ptr key3(fabric_peer_key); + ComponentNHKeyPtr component_nh_data3(new ComponentNHKey(0, key3)); + component_nh_list.push_back(component_nh_data3); + } + + if (local_peer_path) { + NextHopKey *local_peer_key = + static_cast((local_peer_path-> + nexthop(agent)->GetDBRequestKey()).release()); + std::auto_ptr key1(local_peer_key); + ComponentNHKeyPtr component_nh_data1(new ComponentNHKey(0, key1)); + component_nh_list.push_back(component_nh_data1); + } + + DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE); + nh_req.key.reset(new CompositeNHKey(Composite::L2COMP, + false, + component_nh_list, + vrf()->GetName())); + nh_req.data.reset(new CompositeNHData()); + agent->nexthop_table()->Process(nh_req); + NextHop *nh = static_cast(agent->nexthop_table()-> + FindActiveEntry(nh_req.key.get())); + //NH may not get added if VRF is marked for delete. Route may be in + //transition of getting deleted, skip NH modification. + if (!nh) { + return false; + } + + bool ret = false; + if (tor_peer_path) { + ret = MulticastRoute::CopyPathParameters(agent, + multicast_peer_path, + (tor_peer_path ? tor_peer_path-> + dest_vn_name() : ""), + (tor_peer_path ? tor_peer_path-> + unresolved() : false), + (tor_peer_path ? tor_peer_path-> + vxlan_id() : 0), + (fabric_peer_path ? fabric_peer_path-> + label() : 0), + TunnelType::VxlanType(), + false, + nh); + } + if (local_peer_path && local_peer_path->nexthop(agent)->GetType() != + NextHop::DISCARD) { + ret = MulticastRoute::CopyPathParameters(agent, + multicast_peer_path, + (local_peer_path ? local_peer_path-> + dest_vn_name() : ""), + (local_peer_path ? local_peer_path-> + unresolved() : false), + (local_peer_path ? local_peer_path-> + vxlan_id() : 0), + (fabric_peer_path ? fabric_peer_path-> + label() : 0), + TunnelType::AllType(), + false, + nh); + } + + //Bake all MPLS label + if (fabric_peer_path) { + if (!ret) { + ret = MulticastRoute::CopyPathParameters(agent, + multicast_peer_path, + (fabric_peer_path ? fabric_peer_path-> + dest_vn_name() : ""), + (fabric_peer_path ? fabric_peer_path-> + unresolved() : false), + (fabric_peer_path ? fabric_peer_path-> + vxlan_id() : 0), + (fabric_peer_path ? fabric_peer_path-> + label() : 0), + TunnelType::MplsType(), + false, + nh); + } + //Add new label + MplsLabel::CreateMcastLabelReq(fabric_peer_path->label(), + Composite::L2COMP, + component_nh_list, + vrf()->GetName()); + //Delete Old label, in case label has changed for same peer. + if (old_fabric_mpls_label != fabric_peer_path->label()) { + MplsLabel::DeleteReq(old_fabric_mpls_label); + } + } + if (evpn_peer_path) { + MplsLabel::CreateMcastLabelReq(evpn_peer_path->label(), + Composite::L2COMP, + component_nh_list, + vrf()->GetName()); + } + return ret; +} diff --git a/src/vnsw/agent/oper/agent_route.h b/src/vnsw/agent/oper/agent_route.h index e2a469dde13..72b80b4f6fa 100644 --- a/src/vnsw/agent/oper/agent_route.h +++ b/src/vnsw/agent/oper/agent_route.h @@ -64,7 +64,8 @@ struct AgentRouteData : public AgentData { virtual ~AgentRouteData() { } virtual std::string ToString() const = 0; - virtual bool AddChangePath(Agent *agent, AgentPath *path) = 0; + virtual bool AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt) = 0; virtual bool IsPeerValid() const {return true;} bool is_multicast() const {return is_multicast_;} @@ -221,9 +222,9 @@ class AgentRoute : public Route { virtual uint32_t GetActiveLabel() const; virtual AgentPath *FindPathUsingKey(const AgentRouteKey *key); virtual void DeletePath(const AgentRouteKey *key); + virtual bool is_multicast() const {return is_multicast_;} // Accessor functions - bool is_multicast() const {return is_multicast_;} VrfEntry *vrf() const {return vrf_.get();} uint32_t vrf_id() const; @@ -248,6 +249,7 @@ class AgentRoute : public Route { void FillTrace(RouteInfo &route, Trace event, const AgentPath *path); bool WaitForTraffic() const; protected: + bool ReComputeMulticastPaths(AgentPath *path, bool del); void SetVrf(VrfEntryRef vrf) { vrf_ = vrf; } void RemovePathInternal(AgentPath *path); void RemovePath(AgentPath *path); diff --git a/src/vnsw/agent/oper/global_vrouter.cc b/src/vnsw/agent/oper/global_vrouter.cc index c1d9c870d5a..bdc6c13f8c4 100644 --- a/src/vnsw/agent/oper/global_vrouter.cc +++ b/src/vnsw/agent/oper/global_vrouter.cc @@ -243,9 +243,9 @@ void GlobalVrouter::LinkLocalRouteManager::AddArpRoute(const Ip4Address &srv) { return; } - InetUnicastAgentRouteTable::CheckAndAddArpReq(global_vrouter_->oper_db()-> - agent()->fabric_vrf_name(), - srv); + Agent *agent = global_vrouter_->oper_db()->agent(); + InetUnicastAgentRouteTable::CheckAndAddArpReq(agent->fabric_vrf_name(), + srv, agent->vhost_interface()); } // Walk thru all the VNs diff --git a/src/vnsw/agent/oper/ifmap_dependency_manager.cc b/src/vnsw/agent/oper/ifmap_dependency_manager.cc index 1c947def45c..a5f75d2d260 100644 --- a/src/vnsw/agent/oper/ifmap_dependency_manager.cc +++ b/src/vnsw/agent/oper/ifmap_dependency_manager.cc @@ -136,12 +136,18 @@ void IFMapDependencyManager::Initialize() { list_of("virtual-machine-service-instance")); policy->insert(make_pair("virtual-machine", react_vm)); + ReactionMap react_li = map_list_of + (("logical-interface-virtual-machine-interface"), list_of("self")); + policy->insert(make_pair("logical-interface", react_li)); + ReactionMap react_vmi = map_list_of ("self", list_of("virtual-machine-interface-virtual-machine")) ("instance-ip-virtual-machine-interface", list_of("virtual-machine-interface-virtual-machine")) ("virtual-machine-interface-virtual-network", - list_of("virtual-machine-interface-virtual-machine")); + list_of("virtual-machine-interface-virtual-machine") + ("virtual-machine-interface-logical-interface") + ("logical-interface-virtual-machine-interface")); policy->insert(make_pair("virtual-machine-interface", react_vmi)); ReactionMap react_ip = map_list_of diff --git a/src/vnsw/agent/oper/inet_interface.cc b/src/vnsw/agent/oper/inet_interface.cc index 73be6111301..7cead1ae1e7 100644 --- a/src/vnsw/agent/oper/inet_interface.cc +++ b/src/vnsw/agent/oper/inet_interface.cc @@ -147,10 +147,25 @@ void InetInterface::DeActivateSimpleGateway() { // Add default route with given gateway static void AddDefaultRoute(Agent *agent, InetUnicastAgentRouteTable *table, - const VrfEntry *vrf, const Ip4Address &gw, - const string &vn_name) { + const VrfEntry *vrf, const Interface *xconnect, + const Ip4Address &gw, const string &vn_name) { + + if (xconnect) { + const PhysicalInterface *physical_intf = + static_cast(xconnect); + if (physical_intf->no_arp() || + (physical_intf->encap_type() == PhysicalInterface::RAW_IP)) { + table->AddInterfaceRouteReq(agent, agent->local_peer(), + vrf->GetName(), Ip4Address(0), 0, + xconnect, vn_name); + return; + } + } - table->AddGatewayRoute(vrf->GetName(), Ip4Address(0), 0, gw, vn_name); + table->AddGatewayRoute(agent->local_peer(), + vrf->GetName(), Ip4Address(0), 0, gw, vn_name, + MplsTable::kInvalidLabel, SecurityGroupList()); + return; } static void DeleteDefaultRoute(Agent *agent, InetUnicastAgentRouteTable *table, @@ -164,25 +179,43 @@ static void DeleteDefaultRoute(Agent *agent, InetUnicastAgentRouteTable *table, // - Resolve route for the subnet address static void AddHostRoutes(Agent *agent, InetUnicastAgentRouteTable *table, const VrfEntry *vrf, const string &interface, - const Ip4Address &addr, int plen, - const string &vn_name) { + const Interface *xconnect, const Ip4Address &addr, + int plen, const string &vn_name) { table->AddVHostRecvRoute(agent->local_peer(), vrf->GetName(), interface, addr, 32, vn_name, false); + const PhysicalInterface *physical_intf = + static_cast(xconnect); + if (physical_intf) { + if (physical_intf->no_arp()) + return; + if (physical_intf->encap_type() != PhysicalInterface::ETHERNET) + return; + } + table->AddVHostSubnetRecvRoute(agent->local_peer(), vrf->GetName(), interface, GetIp4SubnetBroadcastAddress(addr, plen), 32, vn_name, false); - table->AddResolveRoute(vrf->GetName(), - Address::GetIp4SubnetAddress(addr, plen), plen); + InetInterfaceKey intf_key(interface); + table->AddResolveRoute(agent->local_peer(), vrf->GetName(), + Address::GetIp4SubnetAddress(addr, plen), plen, + intf_key, MplsTable::kInvalidLabel, false, vn_name, + SecurityGroupList()); } static void DeleteHostRoutes(Agent *agent, InetUnicastAgentRouteTable *table, - const VrfEntry *vrf, const Ip4Address &addr, - int plen) { + const VrfEntry *vrf, const Interface *xconnect, + const Ip4Address &addr, int plen) { table->Delete(agent->local_peer(), vrf->GetName(), addr, 32); + const PhysicalInterface *physical_intf = + static_cast(xconnect); + if (physical_intf && physical_intf->no_arp()) { + return; + } + table->Delete(agent->local_peer(), vrf->GetName(), Address::GetIp4SubnetAddress(addr, plen), plen); table->Delete(agent->local_peer(), vrf->GetName(), @@ -205,20 +238,25 @@ void InetInterface::ActivateHostInterface() { InetUnicastAgentRouteTable *uc_rt_table = (vrf_table->GetInet4UnicastRouteTable(vrf()->GetName())); if (ip_addr_.to_ulong()) { - AddHostRoutes(agent, uc_rt_table, vrf(), name(), ip_addr_, plen_, - vn_name_); + AddHostRoutes(agent, uc_rt_table, vrf(), name(), xconnect_.get(), + ip_addr_, plen_, vn_name_); } if (gw_.to_ulong()) { - AddDefaultRoute(agent, uc_rt_table, vrf(), gw_, vn_name_); + AddDefaultRoute(agent, uc_rt_table, vrf(), xconnect_.get(), gw_, + vn_name_); } - // Add receive-route for broadcast address - Inet4MulticastAgentRouteTable *mc_rt_table = - static_cast - (VrfTable::GetInstance()->GetInet4MulticastRouteTable(vrf()->GetName())); - mc_rt_table->AddVHostRecvRoute(vrf()->GetName(), name_, - Ip4Address(0xFFFFFFFF), false); + const PhysicalInterface *physical_intf = + static_cast(xconnect_.get()); + if (physical_intf && physical_intf->no_arp() == false) { + // Add receive-route for broadcast address + Inet4MulticastAgentRouteTable *mc_rt_table = + static_cast + (VrfTable::GetInstance()->GetInet4MulticastRouteTable(vrf()->GetName())); + mc_rt_table->AddVHostRecvRoute(vrf()->GetName(), name_, + Ip4Address(0xFFFFFFFF), false); + } ReceiveNHKey nh_key(new InetInterfaceKey(name_), false); flow_key_nh_ = static_cast( agent->nexthop_table()->FindActiveEntry(&nh_key)); @@ -232,19 +270,24 @@ void InetInterface::DeActivateHostInterface() { InetUnicastAgentRouteTable *uc_rt_table = (vrf_table->GetInet4UnicastRouteTable(vrf()->GetName())); if (ip_addr_.to_ulong()) { - DeleteHostRoutes(agent, uc_rt_table, vrf(), ip_addr_, plen_); + DeleteHostRoutes(agent, uc_rt_table, vrf(), xconnect_.get(), ip_addr_, + plen_); } if (gw_.to_ulong()) { DeleteDefaultRoute(agent, uc_rt_table, vrf(), gw_); } - Inet4MulticastAgentRouteTable *mc_rt_table = - static_cast - (VrfTable::GetInstance()->GetInet4MulticastRouteTable(vrf()->GetName())); - // Add receive-route for broadcast address - mc_rt_table->Delete(vrf()->GetName(), Ip4Address(0), - Ip4Address(0xFFFFFFFF)); + const PhysicalInterface *physical_intf = + static_cast(xconnect_.get()); + if (physical_intf && physical_intf->no_arp() == false) { + Inet4MulticastAgentRouteTable *mc_rt_table = + static_cast + (VrfTable::GetInstance()->GetInet4MulticastRouteTable(vrf()->GetName())); + // Add receive-route for broadcast address + mc_rt_table->Delete(vrf()->GetName(), Ip4Address(0), + Ip4Address(0xFFFFFFFF)); + } // Delete receive nexthops ReceiveNH::Delete(agent->nexthop_table(), name_); @@ -265,7 +308,8 @@ InetInterface::InetInterface(const std::string &name, SubType sub_type, const Ip4Address &gw, Interface *xconnect, const std::string &vn_name) : Interface(Interface::INET, nil_uuid(), name, vrf), sub_type_(sub_type), - ip_addr_(ip_addr), plen_(plen), gw_(gw), xconnect_(xconnect), vn_name_(vn_name) { + ip_addr_(ip_addr), plen_(plen), gw_(gw), xconnect_(xconnect), + vn_name_(vn_name) { ipv4_active_ = false; l2_active_ = false; } @@ -301,8 +345,9 @@ void InetInterface::DeActivate() { } } -void InetInterface::Delete() { +bool InetInterface::Delete(const DBRequest *req) { DeActivate(); + return true; } // Interface Activate cannot be done in AllocEntry. It must be done in PostAdd @@ -337,7 +382,8 @@ bool InetInterface::OnChange(InetInterfaceData *data) { if (ip_addr_ != data->ip_addr_ || plen_ != data->plen_) { // Delete routes based on old ip-addr and prefix if (ip_addr_.to_ulong()) { - DeleteHostRoutes(agent, uc_rt_table, vrf(), ip_addr_, plen_); + DeleteHostRoutes(agent, uc_rt_table, vrf(), xconnect_.get(), + ip_addr_, plen_); } ip_addr_ = data->ip_addr_; @@ -345,15 +391,15 @@ bool InetInterface::OnChange(InetInterfaceData *data) { vn_name_ = data->vn_name_; // Add routes for new ip-address and prefix if (data->ip_addr_.to_ulong()) { - AddHostRoutes(agent, uc_rt_table, vrf(), name(), ip_addr_, plen_, - vn_name_); + AddHostRoutes(agent, uc_rt_table, vrf(), name(), xconnect_.get(), + ip_addr_, plen_, vn_name_); } ret = true; } else if (vn_name_ != data->vn_name_) { // Change in vn_name, update route with new VN Name vn_name_ = data->vn_name_; - AddHostRoutes(agent, uc_rt_table, vrf(), name(), ip_addr_, plen_, - vn_name_); + AddHostRoutes(agent, uc_rt_table, vrf(), name(), xconnect_.get(), + ip_addr_, plen_, vn_name_); ret = true; } @@ -366,7 +412,8 @@ bool InetInterface::OnChange(InetInterfaceData *data) { gw_ = data->gw_; // Add route for new gateway if (gw_.to_ulong()) { - AddDefaultRoute(agent, uc_rt_table, vrf(), gw_, vn_name_); + AddDefaultRoute(agent, uc_rt_table, vrf(), xconnect_.get(), gw_, + vn_name_); } ret = true; @@ -385,7 +432,8 @@ void InetInterface::CreateReq(InterfaceTable *table, const std::string &ifname, DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE); req.key.reset(new InetInterfaceKey(ifname)); req.data.reset(new InetInterfaceData(sub_type, vrf_name, Ip4Address(addr), - plen, Ip4Address(gw), xconnect, vn_name)); + plen, Ip4Address(gw), xconnect, + vn_name)); table->Enqueue(&req); } diff --git a/src/vnsw/agent/oper/inet_interface.h b/src/vnsw/agent/oper/inet_interface.h index eceed11f579..b776099e293 100644 --- a/src/vnsw/agent/oper/inet_interface.h +++ b/src/vnsw/agent/oper/inet_interface.h @@ -42,7 +42,7 @@ class InetInterface : public Interface { void PostAdd(); bool OnChange(InetInterfaceData *data); - void Delete(); + bool Delete(const DBRequest *req); void Activate(); void DeActivate(); diff --git a/src/vnsw/agent/oper/inet_unicast_route.cc b/src/vnsw/agent/oper/inet_unicast_route.cc index 8acc12c24d5..066aba301a9 100644 --- a/src/vnsw/agent/oper/inet_unicast_route.cc +++ b/src/vnsw/agent/oper/inet_unicast_route.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include using namespace std; @@ -405,12 +406,26 @@ bool InetUnicastRouteEntry::EcmpDeletePath(AgentPath *path) { } bool InetUnicastRouteEntry::ReComputePathAdd(AgentPath *path) { + Agent *agent = + (static_cast (get_table()))->agent(); + AgentPath *local_path = FindPath(agent->local_peer()); + if (local_path && local_path->is_subnet_discard()) { + return ReComputeMulticastPaths(path, false); + } + // ECMP path are managed by route module. Update ECMP path with // addition of new path return EcmpAddPath(path); } bool InetUnicastRouteEntry::ReComputePathDeletion(AgentPath *path) { + Agent *agent = + (static_cast (get_table()))->agent(); + AgentPath *local_path = FindPath(agent->local_peer()); + if (local_path && local_path->is_subnet_discard()) { + return ReComputeMulticastPaths(path, true); + } + // ECMP path are managed by route module. Update ECMP path with // deletion of new path return EcmpDeletePath(path); @@ -590,29 +605,46 @@ const NextHop* InetUnicastRouteEntry::GetLocalNextHop() const { return NULL; } +bool InetUnicastRouteEntry::is_multicast() const { + Agent *agent = + (static_cast (get_table()))->agent(); + const AgentPath *path = FindPath(agent->local_peer()); + if (AgentRoute::is_multicast() || (path && path->is_subnet_discard())) + return true; + return false; +} + ///////////////////////////////////////////////////////////////////////////// // AgentRouteData virtual functions ///////////////////////////////////////////////////////////////////////////// -bool Inet4UnicastArpRoute::AddChangePath(Agent *agent, AgentPath *path) { - bool ret = false; +bool Inet4UnicastArpRoute::AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt) { + bool ret = true; - ArpNHKey key(vrf_name_, addr_); + ArpNHKey key(vrf_name_, addr_, policy_); NextHop *nh = static_cast(agent->nexthop_table()->FindActiveEntry(&key)); path->set_unresolved(false); - path->set_dest_vn_name(agent->fabric_vn_name()); - if (path->dest_vn_name() != agent->fabric_vn_name()) { + + if (path->dest_vn_name() != vn_) { + path->set_dest_vn_name(vn_); ret = true; } - ret = true; + + if (path->sg_list() != sg_list_) { + path->set_sg_list(sg_list_); + ret = true; + } + if (path->ChangeNH(agent, nh) == true) ret = true; return ret; -} +} -bool Inet4UnicastGatewayRoute::AddChangePath(Agent *agent, AgentPath *path) { +bool Inet4UnicastGatewayRoute::AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *agent_rt) { path->set_vrf_name(vrf_name_); InetUnicastAgentRouteTable *table = NULL; @@ -622,20 +654,62 @@ bool Inet4UnicastGatewayRoute::AddChangePath(Agent *agent, AgentPath *path) { if (rt == NULL || rt->plen() == 0) { path->set_unresolved(true); } else if (rt->GetActiveNextHop()->GetType() == NextHop::RESOLVE) { + const ResolveNH *nh = + static_cast(rt->GetActiveNextHop()); path->set_unresolved(true); - InetUnicastAgentRouteTable::AddArpReq(vrf_name_, gw_ip_); + InetUnicastAgentRouteTable::AddArpReq(vrf_name_, gw_ip_, + nh->interface()->vrf()->GetName(), + nh->interface(), nh->PolicyEnabled(), + vn_name_, sg_list_); } else { path->set_unresolved(false); } + if (path->label() != mpls_label_) { + path->set_label(mpls_label_); + } + + SecurityGroupList path_sg_list; + path_sg_list = path->sg_list(); + if (path_sg_list != sg_list_) { + path->set_sg_list(sg_list_); + } + //Reset to new gateway route, no nexthop for indirect route path->set_gw_ip(gw_ip_); path->ResetDependantRoute(rt); + if (path->dest_vn_name() != vn_name_) { + path->set_dest_vn_name(vn_name_); + } + + return true; +} + +Inet4UnicastInterfaceRoute::Inet4UnicastInterfaceRoute +(const PhysicalInterface *interface, const std::string &vn_name) : + AgentRouteData(false), + interface_key_(new PhysicalInterfaceKey(interface->name())), + vn_name_(vn_name) { +} + +bool Inet4UnicastInterfaceRoute::AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *rt) { + bool ret = false; + + path->set_unresolved(false); if (path->dest_vn_name() != agent->fabric_vn_name()) { path->set_dest_vn_name(agent->fabric_vn_name()); + ret = true; } - return true; + InterfaceNHKey key(interface_key_->Clone(), false, InterfaceNHFlags::INET4); + NextHop *nh = static_cast + (agent->nexthop_table()->FindActiveEntry(&key)); + if (path->ChangeNH(agent, nh) == true) { + ret = true; + } + + return ret; } ///////////////////////////////////////////////////////////////////////////// @@ -897,6 +971,18 @@ InetUnicastAgentRouteTable::AddLocalVmRouteReq(const Peer *peer, AddLocalVmRouteReq(peer, vm_vrf, addr, plen, data); } +void +InetUnicastAgentRouteTable::AddClonedLocalPathReq(const Peer *peer, + const string &vm_vrf, + const IpAddress &addr, + uint8_t plen, + ClonedLocalPath *data) { + DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE); + req.key.reset(new InetUnicastRouteKey(peer, vm_vrf, addr, plen)); + req.data.reset(data); + Inet4UnicastTableEnqueue(Agent::GetInstance(), &req); +} + // Create Route for a local VM // Assumes that Interface-NH for "VM Port" is already present void @@ -956,7 +1042,7 @@ InetUnicastAgentRouteTable::AddSubnetBroadcastRoute(const Peer *peer, } void -InetUnicastAgentRouteTable::AddRemoteVmRouteReq(const Peer *peer, +InetUnicastAgentRouteTable::AddRemoteVmRouteReq(const Peer *peer, const string &vm_vrf, const IpAddress &vm_addr, uint8_t plen, @@ -970,32 +1056,41 @@ InetUnicastAgentRouteTable::AddRemoteVmRouteReq(const Peer *peer, } void -InetUnicastAgentRouteTable::AddArpReq(const string &vrf_name, - const Ip4Address &ip) { +InetUnicastAgentRouteTable::AddArpReq(const string &route_vrf_name, + const Ip4Address &ip, + const string &nexthop_vrf_name, + const Interface *intf, bool policy, + const std::string &vn_name, + const SecurityGroupList &sg_list) { Agent *agent = Agent::GetInstance(); DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE); - nh_req.key.reset(new ArpNHKey(vrf_name, ip)); - nh_req.data.reset(new ArpNHData()); + nh_req.key.reset(new ArpNHKey(route_vrf_name, ip, policy)); + nh_req.data.reset(new ArpNHData( + static_cast(intf->GetDBRequestKey().release()))); agent->nexthop_table()->Enqueue(&nh_req); DBRequest rt_req(DBRequest::DB_ENTRY_ADD_CHANGE); rt_req.key.reset(new InetUnicastRouteKey(agent->local_peer(), - vrf_name, ip, 32)); - rt_req.data.reset(new Inet4UnicastArpRoute(vrf_name, ip)); + route_vrf_name, ip, 32)); + rt_req.data.reset(new Inet4UnicastArpRoute(nexthop_vrf_name, ip, policy, + vn_name, sg_list)); Inet4UnicastTableEnqueue(agent, &rt_req); } void InetUnicastAgentRouteTable::ArpRoute(DBRequest::DBOperation op, + const string &route_vrf_name, const Ip4Address &ip, const MacAddress &mac, - const string &vrf_name, + const string &nexthop_vrf_name, const Interface &intf, bool resolved, - const uint8_t plen) { + const uint8_t plen, + bool policy, const std::string &vn_name, + const SecurityGroupList &sg) { Agent *agent = Agent::GetInstance(); DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE); - nh_req.key.reset(new ArpNHKey(vrf_name, ip)); + nh_req.key.reset(new ArpNHKey(nexthop_vrf_name, ip, policy)); ArpNHData *arp_data = new ArpNHData(mac, static_cast(intf.GetDBRequestKey().release()), resolved); @@ -1003,17 +1098,17 @@ InetUnicastAgentRouteTable::ArpRoute(DBRequest::DBOperation op, DBRequest rt_req(op); InetUnicastRouteKey *rt_key = - new InetUnicastRouteKey(agent->local_peer(), vrf_name, ip, plen); + new InetUnicastRouteKey(agent->local_peer(), route_vrf_name, ip, plen); Inet4UnicastArpRoute *data = NULL; switch(op) { case DBRequest::DB_ENTRY_ADD_CHANGE: agent->nexthop_table()->Enqueue(&nh_req); - data = new Inet4UnicastArpRoute(vrf_name, ip); + data = new Inet4UnicastArpRoute(nexthop_vrf_name, ip, policy, vn_name, sg); break; case DBRequest::DB_ENTRY_DELETE: { - VrfEntry *vrf = agent->vrf_table()->FindVrfFromName(vrf_name); + VrfEntry *vrf = agent->vrf_table()->FindVrfFromName(route_vrf_name); InetUnicastRouteEntry *rt = static_cast(vrf-> GetInet4UnicastRouteTable()->Find(rt_key)); @@ -1022,7 +1117,8 @@ InetUnicastAgentRouteTable::ArpRoute(DBRequest::DBOperation op, // If no other route is dependent on this, remove the route; else ignore if (rt && rt->IsDependantRouteEmpty() && rt->IsTunnelNHListEmpty()) { - data = new Inet4UnicastArpRoute(vrf_name, ip); + data = new Inet4UnicastArpRoute(nexthop_vrf_name, ip, policy, + vn_name, sg); } else { rt_key->sub_op_ = AgentKey::RESYNC; rt_req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; @@ -1041,7 +1137,8 @@ InetUnicastAgentRouteTable::ArpRoute(DBRequest::DBOperation op, void InetUnicastAgentRouteTable::CheckAndAddArpReq(const string &vrf_name, - const Ip4Address &ip) { + const Ip4Address &ip, + const Interface *intf) { if (ip == Agent::GetInstance()->router_id() || !IsIp4SubnetMember(ip, Agent::GetInstance()->router_id(), @@ -1050,17 +1147,25 @@ InetUnicastAgentRouteTable::CheckAndAddArpReq(const string &vrf_name, // Currently, default GW Arp is added during init return; } - AddArpReq(vrf_name, ip); + //AddArpReq(vrf_name, ip, intf->vrf()->GetName(), intf); } -void InetUnicastAgentRouteTable::AddResolveRoute(const string &vrf_name, +void InetUnicastAgentRouteTable::AddResolveRoute(const Peer *peer, + const string &vrf_name, const Ip4Address &ip, - const uint8_t plen) { + const uint8_t plen, + const InterfaceKey &intf, + const uint32_t label, + bool policy, + const std::string &vn_name, + const SecurityGroupList + &sg_list) { Agent *agent = Agent::GetInstance(); + ResolveNH::Create(&intf, policy); DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE); - req.key.reset(new InetUnicastRouteKey(agent->local_peer(), vrf_name, ip, + req.key.reset(new InetUnicastRouteKey(peer, vrf_name, ip, plen)); - req.data.reset(new ResolveRoute()); + req.data.reset(new ResolveRoute(&intf, policy, label, vn_name, sg_list)); Inet4UnicastTableEnqueue(agent, &req); } @@ -1163,34 +1268,47 @@ void InetUnicastAgentRouteTable::DelVHostSubnetRecvRoute(const string &vm_vrf, Address::GetIp4SubnetAddress(addr, plen), 32, NULL); } -static void AddGatewayRouteInternal(DBRequest *req, const string &vrf_name, +static void AddGatewayRouteInternal(const Peer *peer, + DBRequest *req, const string &vrf_name, const Ip4Address &dst_addr, uint8_t plen, const Ip4Address &gw_ip, - const string &vn_name) { + const string &vn_name, uint32_t label, + const SecurityGroupList &sg_list) { req->oper = DBRequest::DB_ENTRY_ADD_CHANGE; - req->key.reset(new InetUnicastRouteKey(Agent::GetInstance()->local_peer(), - vrf_name, dst_addr, plen)); - req->data.reset(new Inet4UnicastGatewayRoute(gw_ip, vrf_name)); + req->key.reset(new InetUnicastRouteKey(peer, + vrf_name, dst_addr, plen)); + req->data.reset(new Inet4UnicastGatewayRoute(gw_ip, vrf_name, + vn_name, label, sg_list)); } -void InetUnicastAgentRouteTable::AddGatewayRoute(const string &vrf_name, +void InetUnicastAgentRouteTable::AddGatewayRoute(const Peer *peer, + const string &vrf_name, const Ip4Address &dst_addr, uint8_t plen, const Ip4Address &gw_ip, - const string &vn_name) { + const string &vn_name, + uint32_t label, + const SecurityGroupList + &sg_list) { DBRequest req; - AddGatewayRouteInternal(&req, vrf_name, dst_addr, plen, gw_ip, vn_name); + AddGatewayRouteInternal(peer, &req, vrf_name, dst_addr, plen, gw_ip, vn_name, + label, sg_list); Inet4UnicastTableProcess(Agent::GetInstance(), vrf_name, req); } void -InetUnicastAgentRouteTable::AddGatewayRouteReq(const string &vrf_name, +InetUnicastAgentRouteTable::AddGatewayRouteReq(const Peer *peer, + const string &vrf_name, const Ip4Address &dst_addr, uint8_t plen, const Ip4Address &gw_ip, - const string &vn_name) { + const string &vn_name, + uint32_t label, + const SecurityGroupList + &sg_list) { DBRequest req; - AddGatewayRouteInternal(&req, vrf_name, dst_addr, plen, gw_ip, vn_name); + AddGatewayRouteInternal(peer, &req, vrf_name, dst_addr, plen, gw_ip, + vn_name, label, sg_list); Inet4UnicastTableEnqueue(Agent::GetInstance(), &req); } @@ -1255,3 +1373,21 @@ InetUnicastAgentRouteTable::AddSubnetRoute(const string &vrf_name, table->Process(req); } } + +void +InetUnicastAgentRouteTable::AddInterfaceRouteReq(Agent *agent, const Peer *peer, + const string &vrf_name, + const Ip4Address &ip, + uint8_t plen, + const Interface *interface, + const string &vn_name) { + + assert(interface->type() == Interface::PHYSICAL); + DBRequest rt_req(DBRequest::DB_ENTRY_ADD_CHANGE); + rt_req.key.reset(new InetUnicastRouteKey(agent->local_peer(), + vrf_name, ip, plen)); + const PhysicalInterface *phy_intf = static_cast + (interface); + rt_req.data.reset(new Inet4UnicastInterfaceRoute(phy_intf, vn_name)); + Inet4UnicastTableEnqueue(agent, &rt_req); +} diff --git a/src/vnsw/agent/oper/inet_unicast_route.h b/src/vnsw/agent/oper/inet_unicast_route.h index 99107d8953a..9fd542d208a 100644 --- a/src/vnsw/agent/oper/inet_unicast_route.h +++ b/src/vnsw/agent/oper/inet_unicast_route.h @@ -8,6 +8,7 @@ class VlanNhRoute; class LocalVmRoute; class InetInterfaceRoute; +class ClonedLocalPath; ////////////////////////////////////////////////////////////////// // UNICAST INET @@ -69,6 +70,7 @@ class InetUnicastRouteEntry : public AgentRoute { virtual bool ReComputePathAdd(AgentPath *path); virtual bool EcmpAddPath(AgentPath *path); virtual bool EcmpDeletePath(AgentPath *path); + virtual bool is_multicast() const; void AppendEcmpPath(Agent *agent, AgentPath *path); void DeleteComponentNH(Agent *agent, AgentPath *path); @@ -156,6 +158,11 @@ class InetUnicastAgentRouteTable : public AgentRouteTable { InetUnicastRouteEntry *FindRoute(const IpAddress &ip) { return FindLPM(ip); } + + const InetUnicastRouteEntry *GetNext(const InetUnicastRouteEntry *rt) { + return static_cast(tree_.FindNext(rt)); + } + static DBTableBase *CreateTable(DB *db, const std::string &name); static void ReEvaluatePaths(const string &vrf_name, const IpAddress &ip, uint8_t plen); @@ -214,17 +221,32 @@ class InetUnicastAgentRouteTable : public AgentRouteTable { InetUnicastRouteEntry *FindResolveRoute(const Ip4Address &ip); static InetUnicastRouteEntry *FindResolveRoute(const string &vrf_name, const Ip4Address &ip); - static void CheckAndAddArpReq(const string &vrf_name, const Ip4Address &ip); - static void AddArpReq(const string &vrf_name, const Ip4Address &ip); + static void CheckAndAddArpReq(const string &vrf_name, const Ip4Address &ip, + const Interface *intf); + static void AddArpReq(const string &route_vrf_name, + const Ip4Address &ip, + const string &nh_vrf_name, + const Interface *intf, + bool policy, const string &dest_vn_name, + const SecurityGroupList &sg_list); static void ArpRoute(DBRequest::DBOperation op, + const string &route_vrf_name, const Ip4Address &ip, const MacAddress &mac, - const string &vrf_name, + const string &nh_vrf_name, const Interface &intf, bool resolved, - const uint8_t plen); - static void AddResolveRoute(const string &vrf_name, const Ip4Address &ip, - const uint8_t plen); + const uint8_t plen, + bool policy, + const string &dest_vn_name, + const SecurityGroupList &sg_list); + static void AddResolveRoute(const Peer *peer, + const string &vrf_name, const Ip4Address &ip, + const uint8_t plen, + const InterfaceKey &intf_key, + const uint32_t label, bool policy, + const std::string &vn_name, + const SecurityGroupList &sg_list); void AddInetInterfaceRouteReq(const Peer *peer, const string &vm_vrf, const Ip4Address &addr, uint8_t plen, InetInterfaceRoute *data); @@ -250,17 +272,29 @@ class InetUnicastAgentRouteTable : public AgentRouteTable { static void AddDropRoute(const string &vm_vrf, const Ip4Address &addr, uint8_t plen, const string &vn_name); - static void AddGatewayRoute(const string &vrf_name, + static void AddGatewayRoute(const Peer *peer, + const string &vrf_name, const Ip4Address &dst_addr,uint8_t plen, const Ip4Address &gw_ip, - const std::string &vn_name); - static void AddGatewayRouteReq(const string &vrf_name, + const std::string &vn_name, uint32_t label, + const SecurityGroupList &sg_list); + static void AddGatewayRouteReq(const Peer *peer, + const string &vrf_name, const Ip4Address &dst_addr,uint8_t plen, const Ip4Address &gw_ip, - const std::string &vn_name); + const std::string &vn_name, uint32_t label, + const SecurityGroupList &sg_list); void AddSubnetRoute(const string &vm_vrf, const IpAddress &addr, uint8_t plen, const string &vn_name, uint32_t vxlan_id); + void AddInterfaceRouteReq(Agent *agent, const Peer *peer, + const string &vrf_name, + const Ip4Address &ip, uint8_t plen, + const Interface *interface, + const std::string &vn_name); + void AddClonedLocalPathReq(const Peer *peer, const string &vm_vrf, + const IpAddress &addr, + uint8_t plen, ClonedLocalPath *data); private: Agent::RouteTableType type_; diff --git a/src/vnsw/agent/oper/interface.cc b/src/vnsw/agent/oper/interface.cc index 925ca0cfc40..2d4e5637939 100644 --- a/src/vnsw/agent/oper/interface.cc +++ b/src/vnsw/agent/oper/interface.cc @@ -109,14 +109,16 @@ bool InterfaceTable::Resync(DBEntry *entry, DBRequest *req) { VmInterfaceData *vm_data = static_cast(req->data.get()); VmInterface *intf = static_cast(entry); - return intf->Resync(vm_data); + return intf->Resync(this, vm_data); } bool InterfaceTable::Delete(DBEntry *entry, const DBRequest *req) { Interface *intf = static_cast(entry); - intf->Delete(); - intf->SendTrace(Interface::DELETE); - return true; + if (intf->Delete(req)) { + intf->SendTrace(Interface::DELETE); + return true; + } + return false; } VrfEntry *InterfaceTable::FindVrfRef(const string &name) const { @@ -338,8 +340,9 @@ void PacketInterface::PostAdd() { InterfaceNH::CreatePacketInterfaceNh(name_); } -void PacketInterface::Delete() { +bool PacketInterface::Delete(const DBRequest *req) { flow_key_nh_= NULL; + return true; } // Enqueue DBRequest to create a Pkt Interface @@ -377,9 +380,10 @@ void PacketInterface::Delete(InterfaceTable *table, const std::string &ifname) { // Ethernet Interface routines ///////////////////////////////////////////////////////////////////////////// PhysicalInterface::PhysicalInterface(const std::string &name, VrfEntry *vrf, - SubType subtype) : + SubType subtype, EncapType encap, + bool no_arp) : Interface(Interface::PHYSICAL, nil_uuid(), name, vrf), - persistent_(false), subtype_(subtype) { + persistent_(false), subtype_(subtype), encap_type_(encap), no_arp_(no_arp) { if (subtype_ == VMWARE) persistent_ = true; } @@ -398,20 +402,25 @@ DBEntryBase::KeyPtr PhysicalInterface::GetDBRequestKey() const { return DBEntryBase::KeyPtr(key); } +void PhysicalInterface::Add() { +} + // Enqueue DBRequest to create a Host Interface void PhysicalInterface::CreateReq(InterfaceTable *table, const string &ifname, - const string &vrf_name, SubType subtype) { + const string &vrf_name, SubType subtype, + EncapType encap, bool no_arp) { DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE); req.key.reset(new PhysicalInterfaceKey(ifname)); - req.data.reset(new PhysicalInterfaceData(vrf_name, subtype)); + req.data.reset(new PhysicalInterfaceData(vrf_name, subtype, encap, no_arp)); table->Enqueue(&req); } void PhysicalInterface::Create(InterfaceTable *table, const string &ifname, - const string &vrf_name, SubType subtype) { + const string &vrf_name, SubType subtype, + EncapType encap, bool no_arp) { DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE); req.key.reset(new PhysicalInterfaceKey(ifname)); - req.data.reset(new PhysicalInterfaceData(vrf_name, subtype)); + req.data.reset(new PhysicalInterfaceData(vrf_name, subtype, encap, no_arp)); table->Process(req); } @@ -439,7 +448,8 @@ PhysicalInterfaceKey::~PhysicalInterfaceKey() { } Interface *PhysicalInterfaceKey::AllocEntry(const InterfaceTable *table) const { - return new PhysicalInterface(name_, NULL, PhysicalInterface::INVALID); + return new PhysicalInterface(name_, NULL, PhysicalInterface::INVALID, + PhysicalInterface::ETHERNET, false); } Interface *PhysicalInterfaceKey::AllocEntry(const InterfaceTable *table, @@ -453,12 +463,14 @@ Interface *PhysicalInterfaceKey::AllocEntry(const InterfaceTable *table, const PhysicalInterfaceData *phy_data = static_cast(data); - return new PhysicalInterface(name_, vrf, phy_data->subtype_); + return new PhysicalInterface(name_, vrf, phy_data->subtype_, + phy_data->encap_type_, phy_data->no_arp_); } void PhysicalInterface::PostAdd() { - InterfaceTable *table = static_cast(get_table()); + InterfaceNH::CreatePhysicalInterfaceNh(name_, mac_); + InterfaceTable *table = static_cast(get_table()); if (subtype_ != VMWARE || table->agent()->test_mode()) { return; } @@ -487,13 +499,20 @@ void PhysicalInterface::PostAdd() { close(fd); } +bool PhysicalInterface::Delete(const DBRequest *req) { + InterfaceNH::DeletePhysicalInterfaceNh(name_); + return true; +} + InterfaceKey *PhysicalInterfaceKey::Clone() const { return new PhysicalInterfaceKey(*this); } PhysicalInterfaceData::PhysicalInterfaceData(const std::string &vrf_name, - PhysicalInterface::SubType subtype) - : InterfaceData(), subtype_(subtype) { + PhysicalInterface::SubType subtype, + PhysicalInterface::EncapType encap, + bool no_arp) + : InterfaceData(), subtype_(subtype), encap_type_(encap), no_arp_(no_arp) { EthInit(vrf_name); } @@ -664,24 +683,31 @@ void Interface::SetItfSandeshData(ItfSandeshData &data) const { common_reason += "vn-admin-down "; } - if (vintf->vm() == NULL) { - common_reason += "vm-null "; - } - if (vintf->vrf() == NULL) { common_reason += "vrf-null "; } - if (vintf->os_index() == Interface::kInvalidIndex) { + if (vintf->subnet().is_unspecified() && + vintf->os_index() == Interface::kInvalidIndex) { common_reason += "no-dev "; } - if (vintf->os_oper_state() == false) { - common_reason += "os-state-down "; + if (vintf->NeedDevice()) { + if (vintf->os_index() == Interface::kInvalidIndex) { + common_reason += "no-dev "; + } + + if (vintf->os_oper_state() == false) { + common_reason += "os-state-down "; + } } if (!ipv4_active_) { - string reason = "Inactive< " + common_reason; + if (vintf->layer3_forwarding() == false) { + common_reason += "l3-disabled"; + } + + string reason = "L3 Inactive < " + common_reason; if (vintf->ip_addr().to_ulong() == 0) { reason += "no-ip-addr "; } @@ -690,7 +716,10 @@ void Interface::SetItfSandeshData(ItfSandeshData &data) const { } if (!l2_active_) { - string reason = "Inactive L2< " + common_reason; + if (vintf->layer2_forwarding() == false) { + common_reason += "l2-disabled"; + } + string reason = "L2 Inactive < " + common_reason; reason += " >"; data.set_l2_active(reason); } @@ -807,6 +836,21 @@ void Interface::SetItfSandeshData(ItfSandeshData &data) const { if (vintf->parent()) { data.set_parent_interface(vintf->parent()->name()); } + if (vintf->subnet().to_ulong() != 0) { + std::ostringstream str; + str << vintf->subnet().to_string() << "/" + << (int)vintf->subnet_plen(); + data.set_subnet(str.str()); + } + if (vintf->sub_type() == VmInterface::VCPE) { + data.set_sub_type("VCPE"); + } else if (vintf->sub_type() == VmInterface::TOR) { + data.set_sub_type("TOR"); + } else if (vintf->sub_type() == VmInterface::NOVA) { + data.set_sub_type("Tap"); + } else { + data.set_sub_type("None"); + } break; } case Interface::INET: diff --git a/src/vnsw/agent/oper/interface.h b/src/vnsw/agent/oper/interface.h index 5b1291fe6f1..aabe86d3299 100644 --- a/src/vnsw/agent/oper/interface.h +++ b/src/vnsw/agent/oper/interface.h @@ -65,7 +65,7 @@ class Interface : AgentRefCount, public AgentDBEntry { // virtual functions for specific interface types virtual bool CmpInterface(const DBEntry &rhs) const = 0; - virtual void Delete() { } + virtual bool Delete(const DBRequest *req) { return true; } virtual void Add() { } virtual void SendTrace(Trace event) const; virtual void GetOsParams(Agent *agent); diff --git a/src/vnsw/agent/oper/layer2_route.cc b/src/vnsw/agent/oper/layer2_route.cc index 64c4bbf9af2..b6b5dd6473e 100644 --- a/src/vnsw/agent/oper/layer2_route.cc +++ b/src/vnsw/agent/oper/layer2_route.cc @@ -175,6 +175,22 @@ void Layer2AgentRouteTable::AddLayer2BroadcastRoute(const Peer *peer, Layer2TableEnqueue(Agent::GetInstance(), &req); } +void Layer2AgentRouteTable::AddLayer2ReceiveRoute(const Peer *peer, + const string &vrf_name, + const string &vn_name, + const MacAddress &mac, + const string &interface, + bool policy) { + Agent *agent = Agent::GetInstance(); + DBRequest req; + req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; + req.key.reset(new Layer2RouteKey(peer, vrf_name, mac, 0)); + + PacketInterfaceKey intf_key(nil_uuid(), agent->pkt_interface_name()); + req.data.reset(new HostRoute(intf_key, vn_name)); + + Layer2TableEnqueue(agent, &req); +} void Layer2AgentRouteTable::AddRemoteVmRouteReq(const Peer *peer, const string &vrf_name, @@ -292,151 +308,6 @@ uint32_t Layer2RouteEntry::GetActiveLabel() const { return label; } -bool Layer2RouteEntry::ReComputeMulticastPaths(AgentPath *path, bool del) { - if (path->peer() == NULL) { - return false; - } - - Agent *agent = - (static_cast (get_table()))->agent(); - std::vector delete_paths; - if (del && (path->peer() == agent->multicast_peer())) - return false; - - //Possible paths: - //EVPN path - can be from multiple peers. - //Fabric path - from multicast builder - //Multicast peer - AgentPath *multicast_peer_path = NULL; - AgentPath *local_peer_path = NULL; - AgentPath *evpn_peer_path = NULL; - AgentPath *fabric_peer_path = NULL; - - //Delete path label - if (del) { - MplsLabel::DeleteReq(path->label()); - } - - for (Route::PathList::iterator it = GetPathList().begin(); - it != GetPathList().end(); it++) { - AgentPath *it_path = - static_cast(it.operator->()); - //Handle deletions - if (del && (path->peer() == it_path->peer())) { - continue; - } - - //Handle Add/Changes - if (it_path->peer() == agent->local_vm_peer()) { - local_peer_path = it_path; - } else if (it_path->peer()->GetType() == Peer::BGP_PEER) { - //Pick up the first peer. - if (evpn_peer_path == NULL) - evpn_peer_path = it_path; - } else if (it_path->peer()->GetType() == - Peer::MULTICAST_FABRIC_TREE_BUILDER) { - fabric_peer_path = it_path; - } else if (it_path->peer() == agent->multicast_peer()) { - multicast_peer_path = it_path; - } - } - - //all paths are gone so delete multicast_peer path as well - if ((local_peer_path == NULL) && - (evpn_peer_path == NULL) && - (fabric_peer_path == NULL) && - (multicast_peer_path != NULL)) { - RemovePath(multicast_peer_path); - return true; - } - - uint32_t old_fabric_mpls_label = 0; - if (multicast_peer_path == NULL) { - multicast_peer_path = new AgentPath(agent->multicast_peer(), NULL); - InsertPath(multicast_peer_path); - } else { - old_fabric_mpls_label = multicast_peer_path->label(); - } - - ComponentNHKeyList component_nh_list; - - if (evpn_peer_path) { - NextHopKey *evpn_peer_key = - static_cast((evpn_peer_path-> - nexthop(agent)->GetDBRequestKey()).release()); - std::auto_ptr key2(evpn_peer_key); - ComponentNHKeyPtr component_nh_data2(new ComponentNHKey(0, key2)); - component_nh_list.push_back(component_nh_data2); - } - - if (fabric_peer_path) { - NextHopKey *fabric_peer_key = - static_cast((fabric_peer_path-> - nexthop(agent)->GetDBRequestKey()).release()); - std::auto_ptr key3(fabric_peer_key); - ComponentNHKeyPtr component_nh_data3(new ComponentNHKey(0, key3)); - component_nh_list.push_back(component_nh_data3); - } - - if (local_peer_path) { - NextHopKey *local_peer_key = - static_cast((local_peer_path-> - nexthop(agent)->GetDBRequestKey()).release()); - std::auto_ptr key1(local_peer_key); - ComponentNHKeyPtr component_nh_data1(new ComponentNHKey(0, key1)); - component_nh_list.push_back(component_nh_data1); - } - - DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE); - nh_req.key.reset(new CompositeNHKey(Composite::L2COMP, - false, - component_nh_list, - vrf()->GetName())); - nh_req.data.reset(new CompositeNHData()); - agent->nexthop_table()->Process(nh_req); - NextHop *nh = static_cast(agent->nexthop_table()-> - FindActiveEntry(nh_req.key.get())); - //NH may not get added if VRF is marked for delete. Route may be in - //transition of getting deleted, skip NH modification. - if (!nh) { - return false; - } - - bool ret = MulticastRoute::CopyPathParameters(agent, - multicast_peer_path, - (local_peer_path ? local_peer_path-> - dest_vn_name() : ""), - (local_peer_path ? local_peer_path-> - unresolved() : false), - (local_peer_path ? local_peer_path-> - vxlan_id() : 0), - (fabric_peer_path ? fabric_peer_path-> - label() : 0), - TunnelType::AllType(), - false, - nh); - - //Bake all MPLS label - if (fabric_peer_path) { - //Add new label - MplsLabel::CreateMcastLabelReq(fabric_peer_path->label(), - Composite::L2COMP, - component_nh_list, - vrf()->GetName()); - //Delete Old label, in case label has changed for same peer. - if (old_fabric_mpls_label != fabric_peer_path->label()) { - MplsLabel::DeleteReq(old_fabric_mpls_label); - } - } - if (evpn_peer_path) { - MplsLabel::CreateMcastLabelReq(evpn_peer_path->label(), - Composite::L2COMP, - component_nh_list, - vrf()->GetName()); - } - return ret; -} - string Layer2RouteEntry::ToString() const { return mac_.ToString(); } diff --git a/src/vnsw/agent/oper/layer2_route.h b/src/vnsw/agent/oper/layer2_route.h index 52e6bca8910..274e6a5f230 100644 --- a/src/vnsw/agent/oper/layer2_route.h +++ b/src/vnsw/agent/oper/layer2_route.h @@ -64,6 +64,12 @@ class Layer2AgentRouteTable : public AgentRouteTable { Composite::Type type, ComponentNHKeyList &component_nh_key_list); + static void AddLayer2ReceiveRoute(const Peer *peer, + const string &vrf_name, + const string &vn_name, + const MacAddress &mac, + const string &interface, + bool policy); static void DeleteReq(const Peer *peer, const string &vrf_name, const MacAddress &mac, uint32_t ethernet_tag, @@ -124,8 +130,6 @@ class Layer2RouteEntry : public AgentRoute { const uint32_t GetVmIpPlen() const {return plen_;} private: - bool ReComputeMulticastPaths(AgentPath *path, bool del); - MacAddress mac_; Ip4Address vm_ip_; uint32_t plen_; diff --git a/src/vnsw/agent/oper/mpls.cc b/src/vnsw/agent/oper/mpls.cc index 05dbd945760..3d74c48a3f1 100644 --- a/src/vnsw/agent/oper/mpls.cc +++ b/src/vnsw/agent/oper/mpls.cc @@ -65,6 +65,19 @@ bool MplsTable::OnChange(DBEntry *entry, const DBRequest *req) { return ret; } +bool MplsTable::ChangeNH(MplsLabel *mpls, NextHop *nh) { + if (mpls == NULL) + return false; + + if (mpls->nh_ != nh) { + mpls->nh_ = nh; + assert(nh); + mpls->SyncDependentPath(); + return true; + } + return false; +} + // No Change expected for MPLS Label bool MplsTable::ChangeHandler(MplsLabel *mpls, const DBRequest *req) { bool ret = false; @@ -77,13 +90,7 @@ bool MplsTable::ChangeHandler(MplsLabel *mpls, const DBRequest *req) { nh = static_cast (agent()->nexthop_table()->FindActiveEntry(&key)); } - - if (mpls->nh_ != nh) { - mpls->nh_ = nh; - assert(nh); - mpls->SyncDependentPath(); - ret = true; - } + ret = ChangeNH(mpls, nh); return ret; } @@ -163,6 +170,9 @@ void MplsLabel::CreateVPortLabel(uint32_t label, const uuid &intf_uuid, void MplsLabel::CreateMcastLabelReq(uint32_t label, COMPOSITETYPE type, ComponentNHKeyList &component_nh_key_list, const std::string vrf_name) { + if (label == 0 || label == MplsTable::kInvalidLabel) + return; + DBRequest req; req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; @@ -193,7 +203,29 @@ void MplsLabel::CreateEcmpLabel(uint32_t label, COMPOSITETYPE type, MplsTable::GetInstance()->Process(req); return; } - + +void MplsLabel::CreateTableLabel(uint32_t label, const std::string &vrf_name, + bool policy) { + DBRequest nh_req; + nh_req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; + VrfNHKey *vrf_nh_key = new VrfNHKey(vrf_name, false); + nh_req.key.reset(vrf_nh_key); + nh_req.data.reset(NULL); + Agent::GetInstance()->nexthop_table()->Process(nh_req); + + DBRequest req; + req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; + + MplsLabelKey *key = new MplsLabelKey(MplsLabel::VPORT_NH, label); + req.key.reset(key); + + MplsLabelData *data = new MplsLabelData(vrf_name, policy); + req.data.reset(data); + + MplsTable::GetInstance()->Process(req); + return; +} + void MplsLabel::DeleteMcastLabelReq(uint32_t src_label) { DBRequest req; req.oper = DBRequest::DB_ENTRY_DELETE; diff --git a/src/vnsw/agent/oper/mpls.h b/src/vnsw/agent/oper/mpls.h index 843d596796f..5b0188c6049 100644 --- a/src/vnsw/agent/oper/mpls.h +++ b/src/vnsw/agent/oper/mpls.h @@ -53,6 +53,8 @@ class MplsLabel : AgentRefCount, public AgentDBEntry { static void CreateEcmpLabel(uint32_t label, COMPOSITETYPE type, ComponentNHKeyList &component_nh_key_list, const std::string vrf_name); + static void CreateTableLabel(uint32_t label, const std::string &vrf_name, + bool policy); static void DeleteMcastLabelReq(uint32_t src_label); // Delete MPLS Label entry static void DeleteReq(uint32_t label); @@ -113,6 +115,9 @@ class MplsLabelData : public AgentData { component_nh_key_list, vrf_name)) { } + MplsLabelData(const std::string vrf_name, bool policy) : + AgentData(), nh_key(new VrfNHKey(vrf_name, policy)) { + } virtual ~MplsLabelData() { if (nh_key) { delete nh_key; @@ -151,6 +156,8 @@ class MplsTable : public AgentDBTable { static DBTableBase *CreateTable(DB *db, const std::string &name); static MplsTable *GetInstance() {return mpls_table_;}; void Process(DBRequest &req); + bool ChangeNH(MplsLabel *mpls, NextHop *nh); + private: static MplsTable *mpls_table_; bool ChangeHandler(MplsLabel *mpls, const DBRequest *req); diff --git a/src/vnsw/agent/oper/multicast.cc b/src/vnsw/agent/oper/multicast.cc index db770bace66..d4496fd32c7 100644 --- a/src/vnsw/agent/oper/multicast.cc +++ b/src/vnsw/agent/oper/multicast.cc @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include @@ -24,11 +26,28 @@ #include using namespace std; +using AGENT::PhysicalDeviceVnTable; +using AGENT::PhysicalDeviceTable; +using AGENT::PhysicalDeviceVnEntry; +using AGENT::PhysicalDeviceEntry; + #define INVALID_PEER_IDENTIFIER ControllerPeerPath::kInvalidPeerIdentifier MulticastHandler *MulticastHandler::obj_; SandeshTraceBufferPtr MulticastTraceBuf(SandeshTraceBufferCreate("Multicast", 1000)); + +Composite::Type GetCompositeTypeFromPeer(const Peer *peer) { + if (peer->GetType() == Peer::MULTICAST_TOR_PEER) + return Composite::TOR; + else if (peer->GetType() == Peer::BGP_PEER) + return Composite::EVPN; + else if (peer->GetType() == Peer::MULTICAST_FABRIC_TREE_BUILDER) + return Composite::FABRIC; + else + return Composite::L2INTERFACE; +} + /* * Registeration for notification * VM - Looking for local VM added @@ -40,6 +59,16 @@ void MulticastHandler::Register() { boost::bind(&MulticastHandler::ModifyVN, _1, _2)); interface_listener_id_ = agent_->interface_table()->Register( boost::bind(&MulticastHandler::ModifyVmInterface, _1, _2)); + if (Agent::GetInstance()->tsn_enabled()) { + physical_device_vn_listener_id_ = + agent_->device_manager()->physical_device_vn_table()-> + Register(boost::bind(&MulticastHandler::ModifyTor, + _1, _2)); + physical_device_listener_id_ = + agent_->device_manager()->device_table()-> + Register(boost::bind(&MulticastHandler::ModifyPhysicalDevice, + _1, _2)); + } MulticastHandler::GetInstance()->GetMulticastObjList().clear(); } @@ -62,11 +91,14 @@ void MulticastHandler::AddL2BroadcastRoute(MulticastGroupObject *obj, //Add Layer2 FF:FF:FF:FF:FF:FF ComponentNHKeyList component_nh_key_list = GetInterfaceComponentNHKeyList(obj, InterfaceNHFlags::LAYER2); + if (component_nh_key_list.size() == 0) + return; + uint32_t route_tunnel_bmap = TunnelType::AllType(); Layer2AgentRouteTable::AddLayer2BroadcastRoute(agent_->local_vm_peer(), vrf_name, vn_name, label, vxlan_id, ethernet_tag, - TunnelType::AllType(), + route_tunnel_bmap, Composite::L2INTERFACE, component_nh_key_list); } @@ -81,6 +113,11 @@ void MulticastHandler::DeleteBroadcast(const Peer *peer, boost::system::error_code ec; MCTRACE(Log, "delete bcast route ", vrf_name, "255.255.255.255", 0); Layer2AgentRouteTable::DeleteBroadcastReq(peer, vrf_name, ethernet_tag); + ComponentNHKeyList component_nh_key_list; //dummy list + RebakeSubnetRoute(Agent::GetInstance()->multicast_tor_peer(), + vrf_name, 0, ethernet_tag, "", + true, component_nh_key_list, + GetCompositeTypeFromPeer(peer)); } void MulticastHandler::HandleVxLanChange(const VnEntry *vn) { @@ -92,7 +129,7 @@ void MulticastHandler::HandleVxLanChange(const VnEntry *vn) { if (!obj || obj->IsDeleted()) return; - int new_vxlan_id = vn->GetVxLanId(); + uint32_t new_vxlan_id = vn->GetVxLanId(); if (new_vxlan_id != obj->vxlan_id()) { boost::system::error_code ec; @@ -138,9 +175,282 @@ void MulticastHandler::ModifyVN(DBTablePartBase *partition, DBEntryBase *e) MulticastHandler::GetInstance()->HandleIpam(vn); MulticastHandler::GetInstance()->HandleFamilyConfig(vn); + MulticastHandler::GetInstance()->HandleTor(vn); MulticastHandler::GetInstance()->HandleVxLanChange(vn); } +bool IsTorDeleted(const PhysicalDeviceVnEntry *device_vn, + const PhysicalDeviceEntry *physical_device, + const VnEntry *vn, const VrfEntry *vrf) { + if (device_vn->IsDeleted() || !physical_device || !vn || !vrf) + return true; + + return false; +} + +bool MulticastGroupObject::UpdateTorAddressInOlist(const uuid &device_uuid, + const Ip4Address &ip, + uint32_t vxlan_id) { + bool ret = false; + + for (std::vector::iterator it = tor_olist_.begin(); + it != tor_olist_.end(); it++) { + if ((*it).device_uuid_ == device_uuid) { + (*it).daddr_ = ip; + ret = true; + } + //All TOR have same vxlan in a VN. + if ((*it).label_ != vxlan_id) { + (*it).label_ = vxlan_id; + ret = true; + } + } + return ret; +} + +const OlistTunnelEntry *MulticastGroupObject::FindInTorListUsingUuid +(const uuid &device_uuid) { + for (std::vector::iterator it = tor_olist_.begin(); + it != tor_olist_.end(); it++) { + if ((*it).device_uuid_ == device_uuid) { + return &(*it); + } + } + return NULL; +} + +bool MulticastGroupObject::CanBeDeleted() const { + if (local_olist_.size() == 0 && tor_olist_.empty()) + return true; + return false; +} + +void DeleteTorFromAllMulticastObject(MulticastHandler *mc_handler, + const uuid &device_uuid) +{ + std::set &obj_list = + mc_handler->GetMulticastObjList(); + std::set deleted_obj_list; + for (std::set::iterator it = obj_list.begin(); + it != obj_list.end(); it++) { + MulticastGroupObject *obj = static_cast(*it); + boost::system::error_code ec; + Ip4Address null_ip = IpAddress::from_string("0.0.0.0", + ec).to_v4(); + bool deleted_tor = obj->DeleteFromTorList(device_uuid, + null_ip, + 0, 0, true); + if (!deleted_tor) + continue; + + if (obj->tor_olist().empty()) { + //Delete route path for TOR since olist is empty + Layer2AgentRouteTable::DeleteBroadcastReq(Agent::GetInstance()-> + multicast_tor_peer(), + obj->vrf_name(), + obj->vxlan_id()); + ComponentNHKeyList component_nh_key_list; //dummy list + mc_handler->RebakeSubnetRoute(Agent::GetInstance()->multicast_tor_peer(), + obj->vrf_name(), 0, obj->vxlan_id(), + obj ? obj->GetVnName() : "", + true, component_nh_key_list, + Composite::TOR); + if (obj->CanBeDeleted()) { + MCTRACE(Log, "delete obj vrf/grp/size ", + obj->vrf_name(), obj->GetGroupAddress().to_string(), + mc_handler->GetMulticastObjList().size()); + delete (obj); + mc_handler->GetMulticastObjList().erase(it++); + } + continue; + } + + mc_handler->ModifyTorMembers(Agent::GetInstance()->multicast_tor_peer(), + obj->vrf_name(), + obj->tor_olist(), + obj->vxlan_id(), + 1); + } +} + +void HandleTorRoute(MulticastHandler *mc_handler, + const PhysicalDeviceVnEntry *device_vn_entry) +{ + const PhysicalDeviceEntry *physical_device = device_vn_entry->device(); + const VnEntry *device_vn = device_vn_entry->vn(); + const uuid &device_uuid = device_vn_entry->device_uuid(); + uint32_t vxlan_id = device_vn->GetVxLanId(); + boost::system::error_code ec; + Ip4Address addr = physical_device->ip().to_v4(); + const VrfEntry *device_vn_vrf = device_vn ? device_vn->GetVrf() : NULL; + bool rebake = false; + + //Get the multicast object + MulticastGroupObject *obj = NULL; + if (device_vn_vrf) + obj = mc_handler->FindFloodGroupObject(device_vn_vrf->GetName()); + + //Find out if physical device is deleted. + bool del_tor_request = IsTorDeleted(device_vn_entry, physical_device, + device_vn, device_vn_vrf); + if (del_tor_request) { + //May be VRF is gone from VN before we got the notification, + //so we may be blind to see where this device belonged. + //If device is deleted, walk all multicast objects to check + //for presence of this device and delete it. + if (!device_vn_vrf && device_vn_entry->IsDeleted()) { + DeleteTorFromAllMulticastObject(mc_handler, device_uuid); + return; + } + + //Deletion continues if vrf is known. + //Since there was no object, ignore physical device delete + if (obj == NULL) + return; + obj->DeleteFromTorList(device_uuid, addr, vxlan_id, + TunnelType::VxlanType(), false); + if (obj->tor_olist().empty()) { + //Delete route path for TOR since olist is empty + Layer2AgentRouteTable::DeleteBroadcastReq(Agent::GetInstance()-> + multicast_tor_peer(), + device_vn_vrf->GetName(), + vxlan_id); + ComponentNHKeyList component_nh_key_list; //dummy list + mc_handler->RebakeSubnetRoute(Agent::GetInstance()->multicast_tor_peer(), + device_vn_vrf->GetName(), 0, vxlan_id, "", + true, component_nh_key_list, + Composite::TOR); + MulticastHandler::GetInstance()-> + DeleteMulticastObject(device_vn->GetVrf()->GetName(), addr); + return; + } + //Tor olist is not empty so fallback below to modify member list. + //Code is same for modification with add. + rebake = true; + } else { + if (obj == NULL) { + boost::system::error_code ec; + Ip4Address broadcast = IpAddress::from_string("255.255.255.255", + ec).to_v4(); + obj = MulticastHandler::GetInstance()-> + CreateMulticastGroupObject(device_vn->GetVrf()->GetName(), + broadcast, + device_vn->GetName(), + vxlan_id); + } + + rebake = obj->AddInTorList(device_uuid, addr, vxlan_id, + TunnelType::VxlanType()); + } + + assert(obj != NULL); + + //rebake if VXLAN changed + if (vxlan_id != obj->vxlan_id()) { + obj->set_vxlan_id(vxlan_id); + rebake = true; + } + + //rebake if physical device address changed or any of the + //physical device has changed vxlan + rebake = obj->UpdateTorAddressInOlist(device_vn_entry->device_uuid(), + addr, + vxlan_id); + + if (rebake) { + MulticastHandler::ModifyTorMembers(Agent::GetInstance()-> + multicast_tor_peer(), + device_vn->GetVrf()->GetName(), + obj->tor_olist(), + device_vn->GetVxLanId(), + 1); + } +} + +void MulticastHandler::ModifyTor(DBTablePartBase *partition, DBEntryBase *e) +{ + const PhysicalDeviceVnEntry *device_vn = + static_cast(e); + + HandleTorRoute(MulticastHandler::GetInstance(), device_vn); +} + +void MulticastHandler::ModifyPhysicalDevice(DBTablePartBase *partition, + DBEntryBase *e) +{ + MulticastHandler *handler = MulticastHandler::GetInstance(); + const PhysicalDeviceEntry *device = + static_cast(e); + + //Take IP out of it + const uuid &device_uuid = device->uuid(); + const IpAddress &ip = device->ip(); + + handler->UpdatePhysicalDeviceAddressMap(device_uuid, ip); +} + +void MulticastHandler::UpdatePhysicalDeviceAddressMap(const uuid &device_uuid, + const IpAddress &ip) { + std::map::iterator it = + physical_device_uuid_addr_map_.find(device_uuid); + if ((it == physical_device_uuid_addr_map_.end()) || + (it->second != ip)) { + physical_device_uuid_addr_map_[device_uuid] = ip; + MulticastHandler::GetInstance()->HandleTor(NULL); + } +} + +void MulticastHandler::WalkDone() { + if (physical_device_vn_walker_id_ != DBTableWalker::kInvalidWalkerId) + physical_device_vn_walker_id_ = DBTableWalker::kInvalidWalkerId; +} + +bool MulticastHandler::TorWalker(DBTablePartBase *partition, + DBEntryBase *entry) { + PhysicalDeviceVnEntry *physical_vn_device = + static_cast(entry); + HandleTorRoute(this, physical_vn_device); + return true; +} + +void MulticastHandler::HandleTor(const VnEntry *vn) +{ + if (Agent::GetInstance()->tsn_enabled() == false) { + return; + } + + if ((Agent::GetInstance()->device_manager() == NULL) || + (Agent::GetInstance()->device_manager()->physical_device_vn_table() + == NULL)) { + return; + } + //std::map::iterator it = + // physical_device_vn_walker_id_.find(vn->GetUuid()); + + DBTableWalker *walker = Agent::GetInstance()->db()->GetWalker(); + /// TODO cancel walk + //if (it->second != DBTableWalker::kInvalidWalkerId) + // walker->WalkCancel(it->second); + DBTableWalker::WalkId walk_id = DBTableWalker::kInvalidWalkerId; + //Start a walk on VN table + walk_id = walker->WalkTable(Agent::GetInstance()->device_manager()-> + physical_device_vn_table(), NULL, + boost::bind(&MulticastHandler::TorWalker, this, _1, + _2), + boost::bind(&MulticastHandler::WalkDone, this)); + physical_device_vn_walker_id_ = walk_id; +} + +MulticastGroupObject *MulticastHandler::CreateMulticastGroupObject +(const string &vrf_name, const Ip4Address &ip_addr, const string &vn_name, + uint32_t vxlan_id) { + MulticastGroupObject *obj = + new MulticastGroupObject(vrf_name, ip_addr, vn_name); + obj->set_vxlan_id(vxlan_id); + AddToMulticastObjList(obj); + return obj; +} + void MulticastHandler::HandleIpam(const VnEntry *vn) { const uuid &vn_uuid = vn->GetUuid(); const std::vector &ipam = vn->GetVnIpam(); @@ -186,12 +496,16 @@ void MulticastHandler::ModifyVmInterface(DBTablePartBase *partition, return; } + vm_itf = static_cast(intf); + if (vm_itf->sub_type() == VmInterface::TOR) { + //Ignore TOR VMI, they are not active VMI. + return; + } + if (intf->IsDeleted() || (intf->l2_active() == false)) { MulticastHandler::GetInstance()->DeleteVmInterface(intf); return; } - - vm_itf = static_cast(intf); assert(vm_itf->vn() != NULL); MulticastHandler::GetInstance()->AddVmInterfaceInFloodGroup(vm_itf); @@ -244,13 +558,16 @@ void MulticastHandler::DeleteVmInterface(const Interface *intf) //Delete multicast object for vrf/G void MulticastHandler::DeleteMulticastObject(const std::string &vrf_name, const Ip4Address &grp_addr) { - MCTRACE(Log, "delete obj vrf/grp/size ", vrf_name, grp_addr.to_string(), - this->GetMulticastObjList().size()); for(std::set::iterator it = this->GetMulticastObjList().begin(); it != this->GetMulticastObjList().end(); it++) { if (((*it)->vrf_name() == vrf_name) && ((*it)->GetGroupAddress() == grp_addr)) { + if (!((*it)->CanBeDeleted())) + return; + MCTRACE(Log, "delete obj vrf/grp/size ", vrf_name, + grp_addr.to_string(), + this->GetMulticastObjList().size()); delete (*it); this->GetMulticastObjList().erase(it++); break; @@ -323,13 +640,14 @@ void MulticastHandler::TriggerLocalRouteChange(MulticastGroupObject *obj, obj->GetGroupAddress().to_string(), component_nh_key_list.size()); //Add Layer2 FF:FF:FF:FF:FF:FF, local_vm_peer + uint32_t route_tunnel_bmap = TunnelType::AllType(); Layer2AgentRouteTable::AddLayer2BroadcastRoute(peer, obj->vrf_name(), obj->GetVnName(), obj->evpn_mpls_label(), obj->vxlan_id(), 0, - TunnelType::AllType(), + route_tunnel_bmap, Composite::L2INTERFACE, component_nh_key_list); } @@ -375,13 +693,15 @@ void MulticastHandler::TriggerRemoteRouteChange(MulticastGroupObject *obj, ComponentNHKeyList component_nh_key_list; //dummy list RebakeSubnetRoute(peer, vrf_name, 0, ethernet_tag, obj ? obj->GetVnName() : "", - true, component_nh_key_list); + true, component_nh_key_list, + comp_type); return; } // - Update operation with lower sequence number sent compared to // local identifier, ignore - if (peer_identifier < obj_peer_identifier) { + if ((peer_identifier < obj_peer_identifier) && + (comp_type != Composite::TOR)) { return; } @@ -407,7 +727,11 @@ void MulticastHandler::TriggerRemoteRouteChange(MulticastGroupObject *obj, req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; req.key.reset(key); req.data.reset(tnh_data); - Agent::GetInstance()->nexthop_table()->Enqueue(&req); + if (comp_type == Composite::TOR) + Agent::GetInstance()->nexthop_table()->Process(req); + else + Agent::GetInstance()->nexthop_table()->Enqueue(&req); + MCTRACE(Log, "Enqueue add TOR TUNNEL ", Agent::GetInstance()->fabric_vrf_name(), it->daddr_.to_string(), it->label_); @@ -425,19 +749,23 @@ void MulticastHandler::TriggerRemoteRouteChange(MulticastGroupObject *obj, component_nh_key_list.size()); //Add Layer2 FF:FF:FF:FF:FF:FF$ + uint32_t route_tunnel_bmap = TunnelType::AllType(); + if (comp_type == Composite::TOR) + route_tunnel_bmap = TunnelType::VxlanType(); Layer2AgentRouteTable::AddLayer2BroadcastRoute(peer, obj->vrf_name(), obj->GetVnName(), label, obj->vxlan_id(), ethernet_tag, - TunnelType::AllType(), + route_tunnel_bmap, comp_type, component_nh_key_list); - if (comp_type == Composite::EVPN) { - RebakeSubnetRoute(peer, obj->vrf_name(), label, obj->vxlan_id(), - obj->GetVnName(), false, component_nh_key_list); - } + MCTRACE(Log, "rebake subnet peer for subnet", vrf_name, + "255.255.255.255", comp_type); + RebakeSubnetRoute(peer, obj->vrf_name(), label, obj->vxlan_id(), + obj->GetVnName(), false, component_nh_key_list, + comp_type); } void MulticastHandler::RebakeSubnetRoute(const Peer *peer, @@ -446,12 +774,9 @@ void MulticastHandler::RebakeSubnetRoute(const Peer *peer, uint32_t vxlan_id, const std::string &vn_name, bool del_op, - const ComponentNHKeyList &comp_nh_list) + const ComponentNHKeyList &comp_nh_list, + COMPOSITETYPE comp_type) { - //Expect only to handle EVPN information. - if (peer->GetType() != Peer::BGP_PEER) - return; - std::vector &vrf_ipam = (vrf_ipam_mapping_.find(vrf_name))->second; for (std::vector::iterator it = vrf_ipam.begin(); @@ -464,7 +789,7 @@ void MulticastHandler::RebakeSubnetRoute(const Peer *peer, if (del_op == false) { DBRequest nh_req; nh_req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; - nh_req.key.reset(new CompositeNHKey(Composite::EVPN, false, + nh_req.key.reset(new CompositeNHKey(comp_type, false, comp_nh_list, vrf_name)); nh_req.data.reset(new CompositeNHData()); //add route @@ -497,13 +822,11 @@ void MulticastHandler::AddVmInterfaceInFloodGroup(const VmInterface *vm_itf) { //All broadcast addition 255.255.255.255 all_broadcast = this->FindGroupObject(vrf_name, broadcast); if (all_broadcast == NULL) { - all_broadcast = new MulticastGroupObject(vrf_name, broadcast, - vn_name); - AddToMulticastObjList(all_broadcast); + all_broadcast = CreateMulticastGroupObject(vrf_name, broadcast, + vn_name, vn->GetVxLanId()); add_route = true; } - all_broadcast->set_vxlan_id(vn->GetVxLanId()); //Modify Nexthops if (all_broadcast->AddLocalMember(intf_uuid) == true) { if (vn->layer2_forwarding()) { @@ -631,6 +954,49 @@ void MulticastHandler::ModifyTorMembers(const Peer *peer, MCTRACE(Log, "Add external TOR Olist ", vrf_name, grp.to_string(), 0); } +const OlistTunnelEntry *MulticastGroupObject::FindInTorList +(const uuid &device_uuid, uint32_t vxlan_id, uint32_t tunnel_bmap) { + for (std::vector::iterator it = tor_olist_.begin(); + it != tor_olist_.end(); it++) { + if (((*it).device_uuid_ == device_uuid) && + ((*it).label_ == vxlan_id) && + ((*it).tunnel_bmap_ == tunnel_bmap)) { + return &(*it); + } + } + return NULL; +} + +bool MulticastGroupObject::AddInTorList(const uuid &device_uuid, + const Ip4Address &ip_addr, + uint32_t vxlan_id, + uint32_t tunnel_bmap) { + if (FindInTorListUsingUuid(device_uuid) != NULL) + return false; + + tor_olist_.push_back(OlistTunnelEntry(device_uuid, vxlan_id, ip_addr, + tunnel_bmap)); + return true; +} + +bool MulticastGroupObject::DeleteFromTorList(const uuid &device_uuid, + const Ip4Address &ip_addr, + uint32_t vxlan_id, + uint32_t tunnel_bmap, + bool use_uuid_only) { + for (std::vector::iterator it = tor_olist_.begin(); + it != tor_olist_.end(); it++) { + if ((*it).device_uuid_ == device_uuid) { + if (use_uuid_only || (((*it).label_ == vxlan_id) && + ((*it).tunnel_bmap_ == tunnel_bmap))) { + tor_olist_.erase(it); + return true; + } + } + } + return false; +} + // Helper to delete fabric nh // For internal delete it uses invalid identifier. // For delete via control node it uses the sequence sent. diff --git a/src/vnsw/agent/oper/multicast.h b/src/vnsw/agent/oper/multicast.h index 236f53c6595..fa198f9b293 100644 --- a/src/vnsw/agent/oper/multicast.h +++ b/src/vnsw/agent/oper/multicast.h @@ -25,12 +25,17 @@ do { ((grp.to_ulong() & 0xF0000000) == 0xE0000000)) struct OlistTunnelEntry { - OlistTunnelEntry() : label_(0), daddr_(0), tunnel_bmap_(0) { } - OlistTunnelEntry(uint32_t label, const Ip4Address &addr, + OlistTunnelEntry(const uuid &device_uuid, + uint32_t label, + const Ip4Address &addr, TunnelType::TypeBmap bmap) : - label_(label), daddr_(addr), tunnel_bmap_(bmap) { } + device_uuid_(device_uuid), + label_(label), + daddr_(addr), + tunnel_bmap_(bmap) { } virtual ~OlistTunnelEntry() { } + uuid device_uuid_; uint32_t label_; Ip4Address daddr_; TunnelType::TypeBmap tunnel_bmap_; @@ -49,6 +54,7 @@ class MulticastGroupObject { boost::system::error_code ec; src_address_ = IpAddress::from_string("0.0.0.0", ec).to_v4(); local_olist_.clear(); + tor_olist_.clear(); }; MulticastGroupObject(const std::string &vrf_name, const Ip4Address &grp_addr, @@ -57,9 +63,11 @@ class MulticastGroupObject { evpn_mpls_label_(0), vxlan_id_(0), layer2_forwarding_(true), peer_identifier_(0), deleted_(false) { local_olist_.clear(); + tor_olist_.clear(); }; virtual ~MulticastGroupObject() { }; + bool CanBeDeleted() const; uint32_t evpn_mpls_label() const {return evpn_mpls_label_;} void set_evpn_mpls_label(uint32_t label) {evpn_mpls_label_ = label;} @@ -101,10 +109,25 @@ class MulticastGroupObject { bool layer2_forwarding() const {return layer2_forwarding_;}; void SetLayer2Forwarding(bool enable) {layer2_forwarding_ = enable;}; bool CanUnsubscribe() const {return (deleted_ || !layer2_forwarding_);} - void set_vxlan_id(int vxlan_id) {vxlan_id_ = vxlan_id;} - int vxlan_id() const {return vxlan_id_;} + void set_vxlan_id(uint32_t vxlan_id) {vxlan_id_ = vxlan_id;} + uint32_t vxlan_id() const {return vxlan_id_;} void set_peer_identifier(uint64_t peer_id) {peer_identifier_ = peer_id;} uint64_t peer_identifier() {return peer_identifier_;} + bool AddInTorList(const uuid &device_uuid, + const Ip4Address &ip_addr, + uint32_t vxlan_id, + uint32_t tunnel_bmap); + bool DeleteFromTorList(const uuid &device_uuid, + const Ip4Address &ip_addr, uint32_t vxlan_id, + uint32_t tunnel_bmap, bool use_uuid_only); + const OlistTunnelEntry *FindInTorListUsingUuid(const uuid &device_uuid); + const OlistTunnelEntry *FindInTorList(const uuid &device_uuid, + uint32_t vxlan_id, + uint32_t tunnel_bmap); + const TunnelOlist &tor_olist() const {return tor_olist_;} + bool UpdateTorAddressInOlist(const uuid &device_uuid, + const Ip4Address &ip, + uint32_t vxlan_id); private: @@ -113,11 +136,12 @@ class MulticastGroupObject { std::string vn_name_; Ip4Address src_address_; uint32_t evpn_mpls_label_; - int vxlan_id_; + uint32_t vxlan_id_; bool layer2_forwarding_; uint64_t peer_identifier_; bool deleted_; std::list local_olist_; /* UUID of local i/f */ + TunnelOlist tor_olist_; friend class MulticastHandler; DISALLOW_COPY_AND_ASSIGN(MulticastGroupObject); @@ -130,6 +154,11 @@ class MulticastHandler { MulticastHandler(Agent *agent); virtual ~MulticastHandler() { } + MulticastGroupObject *CreateMulticastGroupObject(const string &vrf_name, + const Ip4Address &ip_addr, + const string &vn_name, + uint32_t vxlan_id); + /* Called by XMPP to add ctrl node sent olist and label */ static void ModifyFabricMembers(const Peer *peer, const std::string &vrf_name, @@ -151,7 +180,14 @@ class MulticastHandler { const TunnelOlist &olist, uint32_t ethernet_tag, uint64_t peer_identifier = 0); - //Registered for VN notification + static void ModifyTor(DBTablePartBase *partition, DBEntryBase *e); + static void ModifyPhysicalDevice(DBTablePartBase *partition, DBEntryBase *e); + void UpdatePhysicalDeviceAddressMap(const uuid &uuid, const IpAddress &ip); + void HandleTor(const VnEntry *vn); + void WalkDone(); + bool TorWalker(DBTablePartBase *partition, DBEntryBase *entry); + + //Registered for VN notification static void ModifyVN(DBTablePartBase *partition, DBEntryBase *e); //Registered for VM notification static void ModifyVmInterface(DBTablePartBase *partition, DBEntryBase *e); @@ -179,7 +215,8 @@ class MulticastHandler { uint32_t vxlan_id, const std::string &vn_name, bool del_op, - const ComponentNHKeyList &comp_nh_list); + const ComponentNHKeyList &comp_nh_list, + COMPOSITETYPE comp_type); void HandleIpam(const VnEntry *vn); void HandleFamilyConfig(const VnEntry *vn); void HandleVxLanChange(const VnEntry *vn); @@ -189,6 +226,9 @@ class MulticastHandler { MulticastGroupObject *FindFloodGroupObject(const std::string &vrf_name); MulticastGroupObject *FindActiveGroupObject(const std::string &vrf_name, const Ip4Address &dip); + std::set &GetMulticastObjList() { + return multicast_obj_list_; + }; MulticastGroupObject *FindGroupObject(const std::string &vrf_name, const Ip4Address &dip); ComponentNHKeyList GetInterfaceComponentNHKeyList(MulticastGroupObject *obj, @@ -197,6 +237,8 @@ class MulticastHandler { void DeleteBroadcast(const Peer *peer, const std::string &vrf_name, uint32_t ethernet_tag); + void DeleteMulticastObject(const std::string &vrf_name, + const Ip4Address &grp_addr); const Agent *agent() const {return agent_;} void Terminate(); @@ -206,12 +248,6 @@ class MulticastHandler { void AddToMulticastObjList(MulticastGroupObject *obj) { multicast_obj_list_.insert(obj); }; - void DeleteMulticastObject(const std::string &vrf_name, - const Ip4Address &grp_addr); - std::set &GetMulticastObjList() { - return this->multicast_obj_list_; - }; - //VM intf add-delete void DeleteVmInterface(const Interface *intf); void AddVmInterfaceInFloodGroup(const VmInterface *vm_itf); @@ -259,6 +295,10 @@ class MulticastHandler { DBTable::ListenerId vn_listener_id_; DBTable::ListenerId interface_listener_id_; + DBTable::ListenerId physical_device_vn_listener_id_;; + DBTable::ListenerId physical_device_listener_id_;; + DBTableWalker::WalkId physical_device_vn_walker_id_; + std::map physical_device_uuid_addr_map_; DISALLOW_COPY_AND_ASSIGN(MulticastHandler); }; diff --git a/src/vnsw/agent/oper/nexthop.cc b/src/vnsw/agent/oper/nexthop.cc index b378d7f086c..106cc0ac70f 100644 --- a/src/vnsw/agent/oper/nexthop.cc +++ b/src/vnsw/agent/oper/nexthop.cc @@ -305,10 +305,12 @@ void ArpNH::SetKey(const DBRequestKey *k) { bool ArpNH::Change(const DBRequest *req) { bool ret= false; + const ArpNHKey *key = static_cast(req->key.get()); const ArpNHData *data = static_cast(req->data.get()); - if (!data->valid_) { - return ret; + if (policy_ != key->policy_) { + policy_ = key->policy_; + ret = true; } if (valid_ != data->resolved_) { @@ -316,18 +318,22 @@ bool ArpNH::Change(const DBRequest *req) { ret = true; } - if (data->resolved_ != true) { - // If ARP is not resolved, interface and mac will be invalid - interface_ = NULL; - return ret; - } - - Interface *interface = NextHopTable::GetInstance()->FindInterface(*data->intf_key_.get()); + Interface *interface = NextHopTable::GetInstance()->FindInterface + (*data->intf_key_.get()); if (interface_.get() != interface) { interface_ = interface; ret = true; } + if (!data->valid_) { + return ret; + } + + if (data->resolved_ != true) { + // If ARP is not resolved mac will be invalid + return ret; + } + if (mac_.CompareTo(data->mac_) != 0) { mac_ = data->mac_; ret = true; @@ -341,7 +347,7 @@ const uint32_t ArpNH::vrf_id() const { } ArpNH::KeyPtr ArpNH::GetDBRequestKey() const { - NextHopKey *key = new ArpNHKey(vrf_->GetName(), ip_); + NextHopKey *key = new ArpNHKey(vrf_->GetName(), ip_, policy_); return DBEntryBase::KeyPtr(key); } @@ -558,6 +564,24 @@ void InterfaceNH::CreatePacketInterfaceNh(const string &ifname) { NextHopTable::GetInstance()->Process(req); } +void InterfaceNH::CreatePhysicalInterfaceNh(const string &ifname, + const MacAddress &mac) { + DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE); + req.key.reset(new InterfaceNHKey(new PhysicalInterfaceKey(ifname), false, + InterfaceNHFlags::INET4)); + req.data.reset(new InterfaceNHData(Agent::GetInstance()->fabric_vrf_name(), + mac)); + NextHopTable::GetInstance()->Process(req); +} + +void InterfaceNH::DeletePhysicalInterfaceNh(const string &ifname) { + DBRequest req(DBRequest::DB_ENTRY_DELETE); + req.key.reset(new InterfaceNHKey(new PhysicalInterfaceKey(ifname), false, + InterfaceNHFlags::INET4)); + req.data.reset(NULL); + NextHopTable::GetInstance()->Process(req); +} + void InterfaceNH::DeleteHostPortReq(const string &ifname) { DBRequest req; req.oper = DBRequest::DB_ENTRY_DELETE; @@ -718,7 +742,23 @@ bool TunnelNH::Change(const DBRequest *req) { //Trigger ARP resolution valid = false; rt_table->AddUnresolvedNH(this); - InetUnicastAgentRouteTable::AddArpReq(GetVrf()->GetName(), dip_); + const ResolveNH *nh = + static_cast(rt->GetActiveNextHop()); + SecurityGroupList sg_list; + std::string vn = ""; + if (nh->interface()->type() == Interface::VM_INTERFACE) { + const VmInterface *vm_intf = + static_cast(nh->interface()); + vm_intf->CopySgIdList(&sg_list); + if (vm_intf->vn()) { + vn = vm_intf->vn()->GetName(); + } + } + InetUnicastAgentRouteTable::AddArpReq(GetVrf()->GetName(), dip_, + nh->interface()->vrf()->GetName(), + nh->interface(), + nh->PolicyEnabled(), + vn, sg_list); rt = NULL; } else { valid = rt->GetActiveNextHop()->IsValid(); @@ -824,7 +864,23 @@ bool MirrorNH::Change(const DBRequest *req) { //Trigger ARP resolution valid = false; rt_table->AddUnresolvedNH(this); - InetUnicastAgentRouteTable::AddArpReq(GetVrf()->GetName(), dip_); + const ResolveNH *nh = + static_cast(rt->GetActiveNextHop()); + SecurityGroupList sg_list; + std::string vn = ""; + if (nh->interface()->type() == Interface::VM_INTERFACE) { + const VmInterface *vm_intf = + static_cast(nh->interface()); + vm_intf->CopySgIdList(&sg_list); + if (vm_intf->vn()) { + vn = vm_intf->vn()->GetName(); + } + } + InetUnicastAgentRouteTable::AddArpReq(GetVrf()->GetName(), dip_, + nh->interface()->vrf()->GetName(), + nh->interface(), + nh->PolicyEnabled(), + vn, sg_list); rt = NULL; } else { valid = rt->GetActiveNextHop()->IsValid(); @@ -940,16 +996,18 @@ void ReceiveNH::SendObjectLog(AgentLogEvent::type event) const { // ResolveNH routines ///////////////////////////////////////////////////////////////////////////// NextHop *ResolveNHKey::AllocEntry() const { - return new ResolveNH(); + Interface *intf = static_cast + (Agent::GetInstance()->interface_table()->Find(intf_key_.get(), true)); + return new ResolveNH(intf, policy_); } bool ResolveNH::CanAdd() const { return true; } -void ResolveNH::Create( ) { +void ResolveNH::Create(const InterfaceKey *intf, bool policy) { DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE); - req.key.reset(new ResolveNHKey()); + req.key.reset(new ResolveNHKey(intf, policy)); req.data.reset(new ResolveNHData()); NextHopTable::GetInstance()->Process(req); } @@ -1432,6 +1490,12 @@ void CompositeNH::ChangeComponentNHKeyTunnelType( if ((*it)->nh_key()->GetType() == NextHop::COMPOSITE) { CompositeNHKey *composite_nh_key = static_cast((*it)->nh_key()->Clone()); + if (composite_nh_key->composite_nh_type() == Composite::TOR) { + type = TunnelType::VXLAN; + } + if (composite_nh_key->composite_nh_type() == Composite::FABRIC) { + type = TunnelType::ComputeType(TunnelType::MplsType()); + } ChangeComponentNHKeyTunnelType( composite_nh_key->component_nh_key_list_, type); std::auto_ptr nh_key(composite_nh_key); @@ -1458,13 +1522,18 @@ void CompositeNH::ChangeComponentNHKeyTunnelType( //would call ChangeTunnelType() API which would result in recursion CompositeNH *CompositeNH::ChangeTunnelType(Agent *agent, TunnelType::Type type) const { + if (composite_nh_type_ == Composite::TOR) { + type = TunnelType::VXLAN; + } + if (composite_nh_type_ == Composite::FABRIC) { + type = TunnelType::ComputeType(TunnelType::MplsType()); + } //Create all component NH with new tunnel type CreateComponentNH(agent, type); //Change the tunnel type of all component NH key ComponentNHKeyList new_component_nh_key_list = component_nh_key_list_; ChangeComponentNHKeyTunnelType(new_component_nh_key_list, type); - //Create the new nexthop CompositeNHKey *comp_nh_key = new CompositeNHKey(composite_nh_type_, policy_, diff --git a/src/vnsw/agent/oper/nexthop.h b/src/vnsw/agent/oper/nexthop.h index e4c607b7d2e..65d610ade41 100644 --- a/src/vnsw/agent/oper/nexthop.h +++ b/src/vnsw/agent/oper/nexthop.h @@ -293,6 +293,13 @@ class TunnelType { static TypeBmap DefaultTypeBmap() {return (1 << DefaultType());} static TypeBmap VxlanType() {return (1 << VXLAN);}; static TypeBmap MplsType() {return ((1 << MPLS_GRE) | (1 << MPLS_UDP));}; + static TypeBmap GetTunnelBmap(TunnelType::Type type) { + if (type == MPLS_GRE || type == MPLS_UDP) + return TunnelType::MplsType(); + if (type == VXLAN) + return TunnelType::VxlanType(); + return TunnelType::AllType(); + } static TypeBmap AllType() {return ((1 << MPLS_GRE) | (1 << MPLS_UDP) | (1 << VXLAN));} static TypeBmap GREType() {return (1 << MPLS_GRE);} @@ -515,7 +522,7 @@ class ReceiveNH : public NextHop { virtual void Delete(const DBRequest *req) {}; virtual void SendObjectLog(AgentLogEvent::type event) const; virtual bool CanAdd() const; - bool NextHopIsLess(const DBEntry &rhs) const { + virtual bool NextHopIsLess(const DBEntry &rhs) const { const ReceiveNH &a = static_cast(rhs); if (interface_.get() != a.interface_.get()) { return interface_.get() < a.interface_.get(); @@ -544,12 +551,15 @@ class ReceiveNH : public NextHop { ///////////////////////////////////////////////////////////////////////////// class ResolveNHKey : public NextHopKey { public: - ResolveNHKey() : NextHopKey(NextHop::RESOLVE, false) { }; + ResolveNHKey(const InterfaceKey *intf_key, bool policy) : + NextHopKey(NextHop::RESOLVE, policy), + intf_key_(intf_key->Clone()) { }; virtual ~ResolveNHKey() { }; virtual NextHop *AllocEntry() const; private: friend class ResolveNH; + boost::scoped_ptr intf_key_; DISALLOW_COPY_AND_ASSIGN(ResolveNHKey); }; @@ -565,7 +575,8 @@ class ResolveNHData : public NextHopData { class ResolveNH : public NextHop { public: - ResolveNH() : NextHop(RESOLVE, true, false) { }; + ResolveNH(const Interface *intf, bool policy) : + NextHop(RESOLVE, true, policy), interface_(intf) { }; virtual ~ResolveNH() { }; virtual std::string ToString() const { return "Resolve"; }; @@ -575,14 +586,25 @@ class ResolveNH : public NextHop { virtual void SetKey(const DBRequestKey *key) { NextHop::SetKey(key); }; virtual bool CanAdd() const; virtual bool NextHopIsLess(const DBEntry &rhs) const { - return false; + const ResolveNH &a = static_cast(rhs); + if (interface_.get() != a.interface_.get()) { + return interface_.get() < a.interface_.get(); + } + + return policy_ < a.policy_; }; virtual KeyPtr GetDBRequestKey() const { - return DBEntryBase::KeyPtr(new ResolveNHKey()); + boost::scoped_ptr intf_key( + static_cast(interface_->GetDBRequestKey().release())); + return DBEntryBase::KeyPtr(new ResolveNHKey(intf_key.get(), policy_)); }; - - static void Create(); + virtual bool DeleteOnZeroRefCount() const { + return true; + } + static void Create(const InterfaceKey *intf, bool policy); + const Interface* interface() const { return interface_.get();} private: + InterfaceConstRef interface_; DISALLOW_COPY_AND_ASSIGN(ResolveNH); }; @@ -591,8 +613,8 @@ class ResolveNH : public NextHop { ///////////////////////////////////////////////////////////////////////////// class ArpNHKey : public NextHopKey { public: - ArpNHKey(const string &vrf_name, const Ip4Address &ip) : - NextHopKey(NextHop::ARP, false), vrf_key_(vrf_name), dip_(ip) { + ArpNHKey(const string &vrf_name, const Ip4Address &ip, bool policy) : + NextHopKey(NextHop::ARP, policy), vrf_key_(vrf_name), dip_(ip) { } virtual ~ArpNHKey() { }; @@ -606,8 +628,8 @@ class ArpNHKey : public NextHopKey { class ArpNHData : public NextHopData { public: - ArpNHData() : - NextHopData(), intf_key_(NULL), + ArpNHData(InterfaceKey *intf_key) : + NextHopData(), intf_key_(intf_key), mac_(), resolved_(false), valid_(false) { }; ArpNHData(const MacAddress &mac, InterfaceKey *intf_key, @@ -825,6 +847,9 @@ class InterfaceNH : public NextHop { static void DeleteNH(const uuid &intf_uuid, bool policy, uint8_t flags); static void DeleteVmInterfaceNHReq(const uuid &intf_uuid); static void CreatePacketInterfaceNh(const string &ifname); + static void CreatePhysicalInterfaceNh(const string &ifname, + const MacAddress &mac); + static void DeletePhysicalInterfaceNh(const string &ifname); static void DeleteHostPortReq(const string &ifname); static void CreateInetInterfaceNextHop(const string &ifname, const string &vrf_name); @@ -848,6 +873,11 @@ class VrfNHKey : public NextHopKey { } virtual ~VrfNHKey() { } + virtual bool NextHopKeyIsLess(const NextHopKey &rhs) const { + const VrfNHKey &key = static_cast(rhs); + return vrf_key_.IsLess(key.vrf_key_); + } + virtual NextHop *AllocEntry() const; virtual NextHopKey *Clone() const { return new VrfNHKey(vrf_key_.name_, policy_); @@ -1120,6 +1150,7 @@ class CompositeNHKey : public NextHopKey { void CreateTunnelNH(Agent *agent); void CreateTunnelNHReq(Agent *agent); void ChangeTunnelType(TunnelType::Type tunnel_type); + COMPOSITETYPE composite_nh_type() const {return composite_nh_type_;} private: friend class CompositeNH; void ExpandLocalCompositeNH(Agent *agent); diff --git a/src/vnsw/agent/oper/packet_interface.h b/src/vnsw/agent/oper/packet_interface.h index 1587169b13d..f10e70e0d72 100644 --- a/src/vnsw/agent/oper/packet_interface.h +++ b/src/vnsw/agent/oper/packet_interface.h @@ -27,7 +27,7 @@ class PacketInterface : public Interface { static void DeleteReq(InterfaceTable *table, const std::string &ifname); static void Delete(InterfaceTable *table, const std::string &ifname); void PostAdd(); - void Delete(); + bool Delete(const DBRequest *req); private: DISALLOW_COPY_AND_ASSIGN(PacketInterface); }; diff --git a/src/vnsw/agent/oper/path_preference.cc b/src/vnsw/agent/oper/path_preference.cc index b9494a14f73..f7058e17012 100644 --- a/src/vnsw/agent/oper/path_preference.cc +++ b/src/vnsw/agent/oper/path_preference.cc @@ -732,9 +732,11 @@ void PathPreferenceModule::IntfNotify(DBTablePartBase *partition, PathPreferenceIntfState *intf_state = static_cast(e->GetState(partition->parent(), intf_id_)); - if (intf->IsDeleted() && intf_state) { - e->ClearState(partition->parent(), intf_id_); - delete intf_state; + if (intf->IsDeleted()) { + if (intf_state) { + e->ClearState(partition->parent(), intf_id_); + delete intf_state; + } return; } diff --git a/src/vnsw/agent/oper/peer.cc b/src/vnsw/agent/oper/peer.cc index 77a1531fad6..4eb023ceffa 100644 --- a/src/vnsw/agent/oper/peer.cc +++ b/src/vnsw/agent/oper/peer.cc @@ -14,16 +14,20 @@ #include #include -Peer::Peer(Type type, const std::string &name) : - type_(type), name_(name){ +Peer::Peer(Type type, const std::string &name, bool export_to_controller) : + type_(type), name_(name), export_to_controller_(export_to_controller) { } Peer::~Peer() { } +const Ip4Address *Peer::NexthopIp(Agent *agent, const AgentPath *path) const { + return agent->router_ip_ptr(); +} + BgpPeer::BgpPeer(const Ip4Address &server_ip, const std::string &name, AgentXmppChannel *bgp_xmpp_peer, DBTableBase::ListenerId id) - : Peer(Peer::BGP_PEER, name), server_ip_(server_ip), id_(id), + : Peer(Peer::BGP_PEER, name, false), server_ip_(server_ip), id_(id), bgp_xmpp_peer_(bgp_xmpp_peer), route_walker_(new ControllerRouteWalker(bgp_xmpp_peer_->agent(), this)) { is_disconnect_walk_ = false; diff --git a/src/vnsw/agent/oper/peer.h b/src/vnsw/agent/oper/peer.h index 3b406044f2c..3c3d16e3564 100644 --- a/src/vnsw/agent/oper/peer.h +++ b/src/vnsw/agent/oper/peer.h @@ -19,31 +19,34 @@ #define ECMP_PEER_NAME "Ecmp" #define VGW_PEER_NAME "Vgw" #define MULTICAST_PEER_NAME "Multicast" +#define MULTICAST_TOR_PEER_NAME "Multicast TOR" #define MULTICAST_FABRIC_TREE_BUILDER_NAME "MulticastTreeBuilder" class AgentXmppChannel; class ControllerRouteWalker; class VrfTable; +class AgentPath; class Peer { public: typedef std::map PeerMap; typedef std::pair PeerPair; enum Type { - MULTICAST_PEER, BGP_PEER, LINKLOCAL_PEER, ECMP_PEER, + LOCAL_VM_PORT_PEER, LOCAL_VM_PEER, LOCAL_PEER, - LOCAL_VM_PORT_PEER, NOVA_PEER, VGW_PEER, + MULTICAST_PEER, MULTICAST_FABRIC_TREE_BUILDER, - OVS_PEER + OVS_PEER, + MULTICAST_TOR_PEER }; - Peer(Type type, const std::string &name); + Peer(Type type, const std::string &name, bool controller_export); virtual ~Peer(); bool IsLess(const Peer *rhs) const { @@ -54,6 +57,10 @@ class Peer { return Compare(rhs); } virtual bool Compare(const Peer *rhs) const {return false;} + // Should we export path from this peer to controller? + virtual bool export_to_controller() const {return export_to_controller_;} + virtual const Ip4Address *NexthopIp(Agent *agent, + const AgentPath *path) const; const std::string &GetName() const { return name_; } const Type GetType() const { return type_; } @@ -61,6 +68,7 @@ class Peer { private: Type type_; std::string name_; + bool export_to_controller_; DISALLOW_COPY_AND_ASSIGN(Peer); }; @@ -123,7 +131,7 @@ class BgpPeer : public Peer { class LocalVmPortPeer : public Peer { public: LocalVmPortPeer(const std::string &name, uint64_t handle) : - Peer(Peer::LOCAL_VM_PORT_PEER, name), handle_(handle) { + Peer(Peer::LOCAL_VM_PORT_PEER, name, true), handle_(handle) { } virtual ~LocalVmPortPeer() { } @@ -142,10 +150,11 @@ class LocalVmPortPeer : public Peer { // ECMP peer class EcmpPeer : public Peer { public: - EcmpPeer() : Peer(Peer::ECMP_PEER, "ECMP") { } + EcmpPeer() : Peer(Peer::ECMP_PEER, "ECMP", true) { } virtual ~EcmpPeer() { } bool Compare(const Peer *rhs) const { return false; } + bool ExportToController() const {return true;} private: DISALLOW_COPY_AND_ASSIGN(EcmpPeer); }; diff --git a/src/vnsw/agent/oper/physical_interface.h b/src/vnsw/agent/oper/physical_interface.h index 4cda1b90877..63f102b2961 100644 --- a/src/vnsw/agent/oper/physical_interface.h +++ b/src/vnsw/agent/oper/physical_interface.h @@ -17,13 +17,21 @@ class PhysicalInterface : public Interface { INVALID }; - PhysicalInterface(const std::string &name, VrfEntry *vrf, SubType subtype); + enum EncapType { + ETHERNET, // Ethernet with ARP + RAW_IP // No L2 header. Packets sent as raw-ip + }; + + PhysicalInterface(const std::string &name, VrfEntry *vrf, SubType subtype, + EncapType encap_type, bool no_arp); virtual ~PhysicalInterface(); bool CmpInterface(const DBEntry &rhs) const; std::string ToString() const { return "ETH <" + name() + ">"; } KeyPtr GetDBRequestKey() const; + virtual void Add(); + virtual bool Delete(const DBRequest *req); void PostAdd(); SubType subtype() const { return subtype_; } @@ -32,24 +40,34 @@ class PhysicalInterface : public Interface { // Currently only vnware physical interface is persistent. // By default every physical interface is non-persistent. bool persistent() const {return persistent_;} + EncapType encap_type() const { return encap_type_; } + bool no_arp() const { return no_arp_; } // Helper functions static void CreateReq(InterfaceTable *table, const std::string &ifname, - const std::string &vrf_name, SubType subtype); + const std::string &vrf_name, SubType subtype, + EncapType encap, bool no_arp); static void Create(InterfaceTable *table, const std::string &ifname, - const std::string &vrf_name, SubType sub_type); + const std::string &vrf_name, SubType sub_type, + EncapType encap, bool no_arp); static void DeleteReq(InterfaceTable *table, const std::string &ifname); static void Delete(InterfaceTable *table, const std::string &ifname); private: bool persistent_; SubType subtype_; + EncapType encap_type_; + bool no_arp_; DISALLOW_COPY_AND_ASSIGN(PhysicalInterface); }; struct PhysicalInterfaceData : public InterfaceData { PhysicalInterfaceData(const std::string &vrf_name, - PhysicalInterface::SubType subtype); + PhysicalInterface::SubType subtype, + PhysicalInterface::EncapType encap, + bool no_arp); PhysicalInterface::SubType subtype_; + PhysicalInterface::EncapType encap_type_; + bool no_arp_; }; struct PhysicalInterfaceKey : public InterfaceKey { diff --git a/src/vnsw/agent/oper/test/test_fabric_interface.cc b/src/vnsw/agent/oper/test/test_fabric_interface.cc index b05e00ab1fd..3f74566b238 100644 --- a/src/vnsw/agent/oper/test/test_fabric_interface.cc +++ b/src/vnsw/agent/oper/test/test_fabric_interface.cc @@ -108,16 +108,18 @@ static void CfgIntfSync(FabricInterfaceTest *t, int id, const char *cfg_name, } static void NovaDel(FabricInterfaceTest *t, int id) { - VmInterface::Delete(t->interface_table_, MakeUuid(id)); + VmInterface::Delete(t->interface_table_, MakeUuid(id), + VmInterface::CONFIG); } static void NovaIntfAdd(FabricInterfaceTest *t, int id, const char *name, const char *addr, const char *mac) { IpAddress ip = Ip4Address::from_string(addr); - VmInterface::Add(t->interface_table_, MakeUuid(id), name, ip.to_v4(), mac, - "", MakeUuid(kProjectUuid), - VmInterface::kInvalidVlanId, VmInterface::kInvalidVlanId, - Agent::NullString(), Ip6Address()); + VmInterface::NovaAdd(t->interface_table_, MakeUuid(id), name, ip.to_v4(), + mac, "", MakeUuid(kProjectUuid), + VmInterface::kInvalidVlanId, + VmInterface::kInvalidVlanId, Agent::NullString(), + Ip6Address()); } // Fabric port with IP Address 0.0.0.0. Needs dhcp_relay diff --git a/src/vnsw/agent/oper/test/test_inet_interface.cc b/src/vnsw/agent/oper/test/test_inet_interface.cc index 1ab3311201a..3aaa40716cf 100644 --- a/src/vnsw/agent/oper/test/test_inet_interface.cc +++ b/src/vnsw/agent/oper/test/test_inet_interface.cc @@ -81,9 +81,9 @@ class InetInterfaceTest : public ::testing::Test { WAIT_FOR(100, 1000, (agent_->vn_table()->Size() == 0U)); } - int intf_count_; - int nh_count_; - int vrf_count_; + uint32_t intf_count_; + uint32_t nh_count_; + uint32_t vrf_count_; Agent *agent_; InterfaceTable *interface_table_; NextHopTable *nh_table_; @@ -284,6 +284,154 @@ TEST_F(InetInterfaceTest, ll_basic_1) { client->WaitForIdle(); } +static void InetTestCleanup(Agent *agent, const Ip4Address &addr, + const Ip4Address &gw, uint8_t plen) { + InetUnicastAgentRouteTable *table = agent->fabric_inet4_unicast_table(); + + table->DeleteReq(agent->local_peer(), agent->fabric_vrf_name(), addr, 32, + NULL); + table->DeleteReq(agent->local_peer(), agent->fabric_vrf_name(), + gw, 32, NULL); + table->DeleteReq(agent->local_peer(), agent->fabric_vrf_name(), + addr, plen, NULL); + WAIT_FOR(1000, 1000, + (RouteGet(agent->fabric_vrf_name(), addr, plen) == NULL)); + client->WaitForIdle(); +} + +static void RestoreInetConfig(Agent *agent) { + InetUnicastAgentRouteTable *table = agent->fabric_inet4_unicast_table(); + AgentParam *param = client->param(); + table->AddGatewayRouteReq(agent->local_peer(), agent->fabric_vrf_name(), + Ip4Address(0), 0, param->vhost_gw(), + agent->fabric_vrf_name(), + MplsTable::kInvalidLabel, SecurityGroupList()); + client->WaitForIdle(); +} + +static void DelInetConfig(Agent *agent) { + InetUnicastAgentRouteTable *table = agent->fabric_inet4_unicast_table(); + table->DeleteReq(agent->local_peer(), agent->fabric_vrf_name(), + Ip4Address(0), 0, NULL); +} + +static bool RouteValidate(Agent *agent, const Ip4Address &ip, uint8_t plen, + NextHop::Type nh_type) { + const InetUnicastRouteEntry *rt = NULL; + const NextHop *nh = NULL; + + WAIT_FOR(1000, 1000, + ((rt = RouteGet(agent->fabric_vrf_name(), ip, plen)) != NULL)); + if (rt == NULL) + return false; + + nh = rt->GetActiveNextHop(); + return (nh->GetType() == nh_type); +} + +TEST_F(InetInterfaceTest, physical_eth_encap_1) { + DelInetConfig(agent_); + + Ip4Address ip = Ip4Address::from_string("10.10.10.10"); + Ip4Address gw = Ip4Address::from_string("10.10.10.1"); + Ip4Address net = Ip4Address::from_string("10.10.10.0"); + uint8_t plen = 24; + + PhysicalInterface::CreateReq(interface_table_, "phy-1", + agent_->fabric_vrf_name(), + PhysicalInterface::FABRIC, + PhysicalInterface::ETHERNET, false); + client->WaitForIdle(); + + InetInterface::CreateReq(interface_table_, "vhost-1", InetInterface::VHOST, + agent_->fabric_vrf_name(), ip, plen, gw, "phy-1", + "TEST"); + client->WaitForIdle(); + + EXPECT_TRUE(RouteValidate(agent_, ip, 32, NextHop::RECEIVE)); + EXPECT_TRUE(RouteValidate(agent_, net, plen, NextHop::RESOLVE)); + + // Cleanup config by the test + InetTestCleanup(agent_, ip, gw, plen); + PhysicalInterface::DeleteReq(interface_table_, "phy-1"); + InetInterface::DeleteReq(interface_table_, "vhost-1"); + client->WaitForIdle(); + + // Restore the vhost and physical-port configuration + RestoreInetConfig(agent_); + client->WaitForIdle(); +} + +TEST_F(InetInterfaceTest, physical_eth_raw_ip_1) { + DelInetConfig(agent_); + + Ip4Address ip = Ip4Address::from_string("10.10.10.10"); + Ip4Address gw = Ip4Address::from_string("10.10.10.1"); + Ip4Address net = Ip4Address::from_string("10.10.10.0"); + uint8_t plen = 24; + + PhysicalInterface::CreateReq(interface_table_, "phy-1", + agent_->fabric_vrf_name(), + PhysicalInterface::FABRIC, + PhysicalInterface::RAW_IP, false); + client->WaitForIdle(); + + InetInterface::CreateReq(interface_table_, "vhost-1", InetInterface::VHOST, + agent_->fabric_vrf_name(), ip, plen, gw, "phy-1", + "TEST"); + client->WaitForIdle(); + + EXPECT_TRUE(RouteValidate(agent_, ip, 32, NextHop::RECEIVE)); + // Subnet route not added when l2-encap is raw-ip + EXPECT_FALSE(RouteFind(agent_->fabric_vrf_name().c_str(), net, plen)); + EXPECT_TRUE(RouteValidate(agent_, Ip4Address(0), 0, NextHop::INTERFACE)); + + // Cleanup config by the test + InetTestCleanup(agent_, ip, gw, plen); + PhysicalInterface::DeleteReq(interface_table_, "phy-1"); + InetInterface::DeleteReq(interface_table_, "vhost-1"); + client->WaitForIdle(); + + // Restore the vhost and physical-port configuration + RestoreInetConfig(agent_); + client->WaitForIdle(); +} + +TEST_F(InetInterfaceTest, physical_eth_no_arp_1) { + DelInetConfig(agent_); + + Ip4Address ip = Ip4Address::from_string("10.10.10.10"); + Ip4Address gw = Ip4Address::from_string("10.10.10.1"); + Ip4Address net = Ip4Address::from_string("10.10.10.0"); + uint8_t plen = 24; + + PhysicalInterface::CreateReq(interface_table_, "phy-1", + agent_->fabric_vrf_name(), + PhysicalInterface::FABRIC, + PhysicalInterface::ETHERNET, true); + client->WaitForIdle(); + + InetInterface::CreateReq(interface_table_, "vhost-1", InetInterface::VHOST, + agent_->fabric_vrf_name(), ip, plen, gw, "phy-1", + "TEST"); + client->WaitForIdle(); + + EXPECT_TRUE(RouteValidate(agent_, ip, 32, NextHop::RECEIVE)); + // Subnet route not added when l2-encap is raw-ip + EXPECT_FALSE(RouteFind(agent_->fabric_vrf_name().c_str(), net, plen)); + EXPECT_TRUE(RouteValidate(agent_, Ip4Address(0), 0, NextHop::INTERFACE)); + + // Cleanup config by the test + InetTestCleanup(agent_, ip, gw, plen); + PhysicalInterface::DeleteReq(interface_table_, "phy-1"); + InetInterface::DeleteReq(interface_table_, "vhost-1"); + client->WaitForIdle(); + + // Restore the vhost and physical-port configuration + RestoreInetConfig(agent_); + client->WaitForIdle(); +} + int main(int argc, char **argv) { GETUSERARGS(); diff --git a/src/vnsw/agent/oper/test/test_intf.cc b/src/vnsw/agent/oper/test/test_intf.cc index 7d153a2c3c9..9ee0674c81b 100644 --- a/src/vnsw/agent/oper/test/test_intf.cc +++ b/src/vnsw/agent/oper/test/test_intf.cc @@ -159,23 +159,28 @@ class IntfTest : public ::testing::Test { } - int intf_count; + uint32_t intf_count; Agent *agent; }; static void NovaIntfAdd(int id, const char *name, const char *addr, const char *mac) { IpAddress ip = Ip4Address::from_string(addr); - VmInterface::Add(Agent::GetInstance()->interface_table(), - MakeUuid(id), name, ip.to_v4(), mac, "", - MakeUuid(kProjectUuid), - VmInterface::kInvalidVlanId, VmInterface::kInvalidVlanId, - Agent::NullString(), Ip6Address()); + VmInterface::NovaAdd(Agent::GetInstance()->interface_table(), + MakeUuid(id), name, ip.to_v4(), mac, "", + MakeUuid(kProjectUuid), VmInterface::kInvalidVlanId, + VmInterface::kInvalidVlanId, Agent::NullString(), + Ip6Address()); } static void NovaDel(int id) { VmInterface::Delete(Agent::GetInstance()->interface_table(), - MakeUuid(id)); + MakeUuid(id), VmInterface::EXTERNAL); +} + +static void ConfigDel(int id) { + VmInterface::Delete(Agent::GetInstance()->interface_table(), + MakeUuid(id), VmInterface::CONFIG); } static void FloatingIpAdd(VmInterface::FloatingIpList &list, const char *addr, @@ -325,7 +330,6 @@ TEST_F(IntfTest, index_reuse) { struct PortInfo input2[] = { {"vnet9", 9, "9.1.1.1", "00:00:00:00:00:01", 1, 1} }; - KSyncSockTypeMap *sock = KSyncSockTypeMap::GetKSyncSockTypeMap(); client->Reset(); CreateVmportEnv(input1, 1); @@ -367,7 +371,6 @@ TEST_F(IntfTest, entry_reuse) { struct PortInfo input1[] = { {"vnet8", 8, "8.1.1.1", "00:00:00:01:01:01", 1, 1} }; - KSyncSockTypeMap *sock = KSyncSockTypeMap::GetKSyncSockTypeMap(); client->Reset(); CreateVmportEnv(input1, 1); @@ -394,7 +397,7 @@ TEST_F(IntfTest, entry_reuse) { EXPECT_FALSE(VmPortFind(8)); } -TEST_F(IntfTest, ActivateInactivate) { +TEST_F(IntfTest, ActivateInactivate_vm) { struct PortInfo input1[] = { {"vnet8", 8, "8.1.1.1", "00:00:00:01:01:01", 1, 1} }; @@ -405,11 +408,34 @@ TEST_F(IntfTest, ActivateInactivate) { EXPECT_TRUE(VmPortFind(8)); client->Reset(); - //Delete VM, and delay deletion of nova - //message (BGP connection drop case) + //Delete VM, and delay deletion of nova + //message (BGP connection drop case) DelLink("virtual-machine", "vm1", "virtual-machine-interface", "vnet8"); DelVm("vm1"); client->WaitForIdle(); + // Interface is active even if VM is deleted + EXPECT_TRUE(VmPortActive(input1, 0)); + DeleteVmportEnv(input1, 1, true); + client->WaitForIdle(); + EXPECT_FALSE(VmPortFind(8)); +} + +TEST_F(IntfTest, ActivateInactivate_vn) { + struct PortInfo input1[] = { + {"vnet8", 8, "8.1.1.1", "00:00:00:01:01:01", 1, 1} + }; + client->Reset(); + CreateVmportEnv(input1, 1); + client->WaitForIdle(); + EXPECT_TRUE(VmPortActive(input1, 0)); + EXPECT_TRUE(VmPortFind(8)); + client->Reset(); + + //Delete VM, and delay deletion of nova + //message (BGP connection drop case) + DelLink("virtual-network", "vn1", "virtual-machine-interface", "vnet8"); + client->WaitForIdle(); + // Interface is active even if VM is deleted EXPECT_FALSE(VmPortActive(input1, 0)); DeleteVmportEnv(input1, 1, true); client->WaitForIdle(); @@ -505,7 +531,7 @@ TEST_F(IntfTest, AddDelVmPortDepOnVmVn_1) { CfgIntfSync(1, "cfg-vnet1", 1, 1, "vrf1", "1.1.1.1"); client->WaitForIdle(); EXPECT_TRUE(client->PortNotifyWait(1)); - EXPECT_TRUE(VmPortInactive(1)); + EXPECT_FALSE(VmPortInactive(1)); EXPECT_TRUE(client->VmNotifyWait(1)); client->Reset(); @@ -545,7 +571,7 @@ TEST_F(IntfTest, AddDelVmPortDepOnVmVn_2_Mirror) { client->Reset(); VnAddReq(1, "vn1", 0, "vrf2"); - CfgIntfSync(1, "cfg-vnet1", 1, 1, NULL_VRF, ZERO_IP); + CfgIntfSync(1, "vnet1", 1, 1, NULL_VRF, ZERO_IP); client->WaitForIdle(); EXPECT_TRUE(client->PortNotifyWait(1)); EXPECT_TRUE(VmPortInactive(1)); @@ -563,7 +589,7 @@ TEST_F(IntfTest, AddDelVmPortDepOnVmVn_2_Mirror) { analyzer_info.dport = 8099; analyzer_info.direction = "both"; VmInterface::FloatingIpList list; - CfgIntfSync(1, "cfg-vnet1", 1, 1, list, "vrf2", "1.1.1.1", analyzer_info); + CfgIntfSync(1, "vnet1", 1, 1, list, "vrf2", "1.1.1.1", analyzer_info); client->WaitForIdle(); MirrorEntryKey mirror_key(analyzer_info.analyzer_name); EXPECT_TRUE(Agent::GetInstance()->mirror_table()->FindActiveEntry(&mirror_key) != NULL); @@ -575,16 +601,16 @@ TEST_F(IntfTest, AddDelVmPortDepOnVmVn_2_Mirror) { analyzer_info.analyzer_ip = "1.1.1.2"; analyzer_info.dport = 8099; analyzer_info.direction = "egress"; - CfgIntfSync(1, "cfg-vnet1", 1, 1, list, "vrf2", "1.1.1.1", analyzer_info); + CfgIntfSync(1, "vnet1", 1, 1, list, "vrf2", "1.1.1.1", analyzer_info); client->WaitForIdle(); EXPECT_EQ(VmPortGetMirrorDirection(1), Interface::MIRROR_TX); client->Reset(); VmDelReq(1); - CfgIntfSync(1, "cfg-vnet1", 1, 1, "vrf2", "1.1.1.1"); + CfgIntfSync(1, "vnet1", 1, 1, "vrf2", "1.1.1.1"); client->WaitForIdle(); EXPECT_TRUE(client->PortNotifyWait(1)); - EXPECT_TRUE(VmPortInactive(1)); + EXPECT_FALSE(VmPortInactive(1)); EXPECT_TRUE(client->VmNotifyWait(1)); EXPECT_EQ(0U, Agent::GetInstance()->vm_table()->Size()); @@ -602,6 +628,9 @@ TEST_F(IntfTest, AddDelVmPortDepOnVmVn_2_Mirror) { VrfDelReq("vrf2"); client->WaitForIdle(); EXPECT_TRUE(Agent::GetInstance()->mirror_table()->FindActiveEntry(&mirror_key) == NULL); + + ConfigDel(1); + client->WaitForIdle(); } // VM create, VMPort create, VN create, VRF create @@ -641,7 +670,7 @@ TEST_F(IntfTest, AddDelVmPortDepOnVmVn_2) { CfgIntfSync(1, "cfg-vnet1", 1, 1, "vrf2", "1.1.1.1"); client->WaitForIdle(); EXPECT_TRUE(client->PortNotifyWait(1)); - EXPECT_TRUE(VmPortInactive(1)); + EXPECT_FALSE(VmPortInactive(1)); EXPECT_TRUE(client->VmNotifyWait(1)); client->Reset(); @@ -657,6 +686,9 @@ TEST_F(IntfTest, AddDelVmPortDepOnVmVn_2) { client->Reset(); VrfDelReq("vrf2"); client->WaitForIdle(); + + ConfigDel(1); + client->WaitForIdle(); } // VM create, VN create, VRF create, 3 VmPorts @@ -719,6 +751,11 @@ TEST_F(IntfTest, MultipleVmPorts_1) { client->Reset(); VrfDelReq("vrf4"); client->WaitForIdle(); + + ConfigDel(1); + ConfigDel(2); + ConfigDel(3); + client->WaitForIdle(); } // VN has ACL set before VM Port is created @@ -802,6 +839,10 @@ TEST_F(IntfTest, VmPortPolicy_1) { client->Reset(); VrfDelReq("vrf5"); client->WaitForIdle(); + + ConfigDel(1); + ConfigDel(2); + client->WaitForIdle(); } // ACL set in VN after VM Port is created @@ -878,6 +919,11 @@ TEST_F(IntfTest, VmPortPolicy_2) { EXPECT_TRUE(client->PortNotifyWait(2)); EXPECT_FALSE(VmPortFind(1)); EXPECT_FALSE(VmPortFind(2)); + + ConfigDel(1); + ConfigDel(2); + client->WaitForIdle(); + WAIT_FOR(100, 1000, (Agent::GetInstance()->interface_table()->Size() == 3U)); WAIT_FOR(100, 1000, (Agent::GetInstance()->vm_table()->Size() == 0U)); @@ -891,6 +937,7 @@ TEST_F(IntfTest, VmPortPolicy_2) { client->Reset(); VrfDelReq("vrf6"); client->WaitForIdle(); + } // Floating IP add @@ -956,6 +1003,8 @@ TEST_F(IntfTest, VmPortFloatingIp_1) { VrfDelReq("vrf1"); VrfDelReq("vrf2"); client->WaitForIdle(); + ConfigDel(1); + client->WaitForIdle(); } // Floating IP add @@ -1034,6 +1083,8 @@ TEST_F(IntfTest, VmPortFloatingIpPolicy_1) { VrfDelReq("vrf1"); VrfDelReq("vrf2"); client->WaitForIdle(); + ConfigDel(1); + client->WaitForIdle(); } TEST_F(IntfTest, VmPortFloatingIpResync_1) { @@ -1137,6 +1188,8 @@ TEST_F(IntfTest, VmPortFloatingIpResync_1) { VrfDelReq("vrf3"); VrfDelReq("vrf4"); client->WaitForIdle(); + ConfigDel(1); + client->WaitForIdle(); } TEST_F(IntfTest, VmPortFloatingIpDelete_1) { @@ -1171,7 +1224,8 @@ TEST_F(IntfTest, VmPortFloatingIpDelete_1) { DelNode("virtual-machine-interface", input[0].name); client->WaitForIdle(); EXPECT_FALSE(RouteFind("default-project:vn2:vn2", floating_ip, 32)); - EXPECT_TRUE(VmPortFloatingIpCount(1, 0)); + // Interface not deleted till config is deleted + EXPECT_TRUE(VmPortFind(1)); //Clean up DelLink("virtual-network", "default-project:vn2", "routing-instance", @@ -1329,7 +1383,8 @@ TEST_F(IntfTest, IntfActivateDeactivate_1) { InterfaceNHKey layer2_policy_nh_key(intf_key5, true, InterfaceNHFlags::LAYER2); EXPECT_FALSE(FindNH(&layer2_policy_nh_key)); - AddNode("virtual-machine-interface", input[0].name, 1); + AddPort(input[0].name, 1); + client->WaitForIdle(); EXPECT_TRUE(FindNH(&unicast_nh_key)); EXPECT_TRUE(FindNH(&unicast_policy_nh_key)); @@ -1456,8 +1511,8 @@ TEST_F(IntfTest, IntfActivateDeactivate_3) { AddVrf("vrf1"); AddLink("virtual-network", "vn1", "routing-instance", "vrf1"); client->WaitForIdle(); - EXPECT_FALSE(FindNH(&unicast_nh_key)); - EXPECT_FALSE(FindNH(&unicast_policy_nh_key)); + EXPECT_TRUE(FindNH(&unicast_nh_key)); + EXPECT_TRUE(FindNH(&unicast_policy_nh_key)); EXPECT_TRUE(FindNH(&multicast_nh_key)); EXPECT_TRUE(FindNH(&layer2_nh_key)); EXPECT_TRUE(FindNH(&layer2_policy_nh_key)); @@ -1522,8 +1577,8 @@ TEST_F(IntfTest, IntfActivateDeactivate_4) { AddVrf("vrf1"); AddLink("virtual-network", "vn1", "routing-instance", "vrf1"); client->WaitForIdle(); - EXPECT_FALSE(FindNH(&unicast_nh_key)); - EXPECT_FALSE(FindNH(&unicast_policy_nh_key)); + EXPECT_TRUE(FindNH(&unicast_nh_key)); + EXPECT_TRUE(FindNH(&unicast_policy_nh_key)); EXPECT_TRUE(FindNH(&multicast_nh_key)); EXPECT_TRUE(FindNH(&layer2_nh_key)); EXPECT_TRUE(FindNH(&layer2_policy_nh_key)); @@ -1636,7 +1691,7 @@ TEST_F(IntfTest, VmPortServiceVlanDelete_1) { DelNode("virtual-machine-interface", input[0].name); client->WaitForIdle(); EXPECT_FALSE(RouteFind("vrf2", service_ip, 32)); - EXPECT_TRUE(VmPortServiceVlanCount(1, 0)); + //EXPECT_TRUE(VmPortServiceVlanCount(1, 0)); DoInterfaceSandesh(""); client->WaitForIdle(); @@ -1690,8 +1745,8 @@ TEST_F(IntfTest, VmPortServiceVlanDelete_2) { //service vlan map gets cleaned up DelLink("virtual-machine", "vm1", "virtual-machine-interface", "vnet1"); client->WaitForIdle(); - EXPECT_FALSE(VmPortActive(input, 0)); - EXPECT_FALSE(RouteFind("vrf2", service_ip, 32)); + EXPECT_TRUE(VmPortActive(input, 0)); + EXPECT_TRUE(RouteFind("vrf2", service_ip, 32)); EXPECT_TRUE(VmPortServiceVlanCount(1, 1)); DoInterfaceSandesh(""); client->WaitForIdle(); @@ -1828,6 +1883,7 @@ TEST_F(IntfTest, VmPortServiceVlanAdd_2) { //Delete the interface, all service vlan routes should be deleted //and interface should be released NovaDel(1); + ConfigDel(1); client->WaitForIdle(); EXPECT_TRUE(VmPortFindRetDel(1) == false); @@ -2143,8 +2199,8 @@ TEST_F(IntfTest, IntfStaticRoute_4) { AddLink("virtual-machine-interface", "vnet1", "interface-route-table", "static_route"); client->WaitForIdle(); - EXPECT_FALSE(RouteFind("vrf1", static_route[0].addr_, - static_route[0].plen_)); + EXPECT_FALSE(RouteFind("vrf1", static_route[0].addr_, + static_route[0].plen_)); EXPECT_FALSE(RouteFind("vrf1", static_route[1].addr_, static_route[1].plen_)); DoInterfaceSandesh("vnet1"); @@ -2468,7 +2524,7 @@ TEST_F(IntfTest, Intf_l2mode_deactivate_activat_via_os_state) { EXPECT_TRUE(VmPortFind(1)); VmInterface *vm_interface = static_cast(VmPortGet(1)); EXPECT_TRUE(vm_interface->vxlan_id() != 0); - uint32_t vxlan_id = vm_interface->vxlan_id(); + int vxlan_id = vm_interface->vxlan_id(); //Deactivate OS state (IF down) DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE); @@ -2559,6 +2615,100 @@ TEST_F(IntfTest, InstanceIpDelete) { client->Reset(); } +TEST_F(IntfTest, VcpeIntfAdd) { + struct PortInfo input1[] = { + {"vnet8", 8, "8.1.1.1", "00:00:00:01:01:01", 1, 1} + }; + + client->Reset(); + CreateVmportWithEcmp(input1, 1); + client->WaitForIdle(); + EXPECT_TRUE(VmPortActive(input1, 0)); + EXPECT_TRUE(VmPortFind(8)); + client->Reset(); + + //Add a link to interface subnet and ensure resolve route is added + AddSubnetType("subnet", 1, "8.1.1.0", 24); + AddLink("virtual-machine-interface", input1[0].name, + "subnet", "subnet"); + client->WaitForIdle(); + EXPECT_TRUE(VmPortActive(input1, 0)); + EXPECT_TRUE(RouteFind("vrf1", "8.1.1.0", 24)); + + //Verify that route is pointing to resolve NH + //and the route points to table NH + Ip4Address addr = Ip4Address::from_string("8.1.1.0"); + InetUnicastRouteEntry *rt = RouteGet("vrf1", addr, 24); + const VnEntry *vn = VnGet(1); + EXPECT_TRUE(rt->GetActiveLabel() == vn->table_label()); + EXPECT_TRUE(rt->GetActiveNextHop()->GetType() == NextHop::RESOLVE); + + DelLink("virtual-machine-interface", input1[0].name, + "subnet", "subnet"); + client->WaitForIdle(); + EXPECT_FALSE(RouteFind("vrf1", "8.1.1.0", 24)); + + DeleteVmportEnv(input1, 1, true); + client->WaitForIdle(); + + EXPECT_FALSE(VmPortFind(8)); + VmInterfaceKey key(AgentKey::ADD_DEL_CHANGE, MakeUuid(8), ""); + WAIT_FOR(100, 1000, (Agent::GetInstance()->interface_table()->Find(&key, true) + == NULL)); + client->Reset(); +} + +TEST_F(IntfTest, VcpeSubnetChange) { + struct PortInfo input1[] = { + {"vnet8", 8, "8.1.1.1", "00:00:00:01:01:01", 1, 1} + }; + + client->Reset(); + CreateVmportWithEcmp(input1, 1); + client->WaitForIdle(); + EXPECT_TRUE(VmPortActive(input1, 0)); + EXPECT_TRUE(VmPortFind(8)); + client->Reset(); + + //Add a link to interface subnet and ensure resolve route is added + AddSubnetType("subnet", 1, "8.1.1.0", 24); + AddLink("virtual-machine-interface", input1[0].name, + "subnet", "subnet"); + client->WaitForIdle(); + EXPECT_TRUE(VmPortActive(input1, 0)); + EXPECT_TRUE(RouteFind("vrf1", "8.1.1.0", 24)); + + //Verify that route is pointing to resolve NH + //and the route points to table NH + Ip4Address addr = Ip4Address::from_string("8.1.1.0"); + InetUnicastRouteEntry *rt = RouteGet("vrf1", addr, 24); + const VnEntry *vn = VnGet(1); + EXPECT_TRUE(rt->GetActiveLabel() == vn->table_label()); + EXPECT_TRUE(rt->GetActiveNextHop()->GetType() == NextHop::RESOLVE); + + AddSubnetType("subnet", 1, "9.1.1.0", 24); + client->WaitForIdle(); + EXPECT_FALSE(RouteFind("vrf1", "8.1.1.0", 24)); + addr = Ip4Address::from_string("9.1.1.0"); + rt = RouteGet("vrf1", addr, 24); + vn = VnGet(1); + EXPECT_TRUE(rt->GetActiveLabel() == vn->table_label()); + EXPECT_TRUE(rt->GetActiveNextHop()->GetType() == NextHop::RESOLVE); + + DelLink("virtual-machine-interface", input1[0].name, + "subnet", "subnet"); + client->WaitForIdle(); + EXPECT_FALSE(RouteFind("vrf1", "9.1.1.0", 24)); + DeleteVmportEnv(input1, 1, true); + client->WaitForIdle(); + + EXPECT_FALSE(VmPortFind(8)); + VmInterfaceKey key(AgentKey::ADD_DEL_CHANGE, MakeUuid(8), ""); + WAIT_FOR(100, 1000, (Agent::GetInstance()->interface_table()->Find(&key, true) + == NULL)); + client->Reset(); +} + int main(int argc, char **argv) { GETUSERARGS(); diff --git a/src/vnsw/agent/oper/test/test_ipv6.cc b/src/vnsw/agent/oper/test/test_ipv6.cc index e987a53b3db..2b80dcc020e 100644 --- a/src/vnsw/agent/oper/test/test_ipv6.cc +++ b/src/vnsw/agent/oper/test/test_ipv6.cc @@ -63,7 +63,7 @@ class Ipv6Test : public ::testing::Test { WAIT_FOR(100, 1000, (agent_->vn_table()->Size() == 0U)); } - int intf_count_; + uint32_t intf_count_; Agent *agent_; }; diff --git a/src/vnsw/agent/oper/test/test_vrf_assign.cc b/src/vnsw/agent/oper/test/test_vrf_assign.cc index 2ea6bc3a905..a21b63796f0 100644 --- a/src/vnsw/agent/oper/test/test_vrf_assign.cc +++ b/src/vnsw/agent/oper/test/test_vrf_assign.cc @@ -24,16 +24,16 @@ static void ValidateSandeshResponse(Sandesh *sandesh, vector &result) { static void NovaIntfAdd(int id, const char *name, const char *addr, const char *mac) { IpAddress ip = Ip4Address::from_string(addr); - VmInterface::Add(Agent::GetInstance()->interface_table(), - MakeUuid(id), name, ip.to_v4(), mac, "", - MakeUuid(kProjectUuid), - VmInterface::kInvalidVlanId, VmInterface::kInvalidVlanId, - Agent::NullString(), Ip6Address()); + VmInterface::NovaAdd(Agent::GetInstance()->interface_table(), + MakeUuid(id), name, ip.to_v4(), mac, "", + MakeUuid(kProjectUuid), VmInterface::kInvalidVlanId, + VmInterface::kInvalidVlanId, Agent::NullString(), + Ip6Address()); } static void NovaDel(int id) { VmInterface::Delete(Agent::GetInstance()->interface_table(), - MakeUuid(id)); + MakeUuid(id), VmInterface::EXTERNAL); } static void CfgIntfSync(int id, const char *cfg_str, int vn, int vm, std::string ) { diff --git a/src/vnsw/agent/oper/vm.cc b/src/vnsw/agent/oper/vm.cc index 5ec4249fbea..df69c21dd95 100644 --- a/src/vnsw/agent/oper/vm.cc +++ b/src/vnsw/agent/oper/vm.cc @@ -121,7 +121,9 @@ bool VmTable::IFNodeToReq(IFMapNode *node, DBRequest &req){ autogen::IdPermsType id_perms = cfg->id_perms(); boost::uuids::uuid u; CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong, u); + string virtual_router_type = "none"; + VmInterface::VmSync(agent()->interface_table(), node); VmKey *key = new VmKey(u); VmData *data = NULL; if (node->IsDeleted()) { diff --git a/src/vnsw/agent/oper/vm_interface.cc b/src/vnsw/agent/oper/vm_interface.cc index 0bd9f7819ac..4686d1ae21d 100644 --- a/src/vnsw/agent/oper/vm_interface.cc +++ b/src/vnsw/agent/oper/vm_interface.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -55,7 +56,9 @@ VmInterface::VmInterface(const boost::uuids::uuid &uuid) : local_preference_(VmInterface::INVALID), oper_dhcp_options_(), sg_list_(), floating_ip_list_(), service_vlan_list_(), static_route_list_(), allowed_address_pair_list_(), vrf_assign_rule_list_(), - vrf_assign_acl_(NULL), vm_ip_gw_addr_(0), vm_ip6_gw_addr_() { + vrf_assign_acl_(NULL), vm_ip_gw_addr_(0), vm_ip6_gw_addr_(), + sub_type_(VmInterface::NONE), configurer_(0), ifmap_node_(NULL), subnet_(0), + subnet_plen_(0) { ipv4_active_ = false; ipv6_active_ = false; l2_active_ = false; @@ -80,7 +83,8 @@ VmInterface::VmInterface(const boost::uuids::uuid &uuid, parent_(parent), local_preference_(VmInterface::INVALID), oper_dhcp_options_(), sg_list_(), floating_ip_list_(), service_vlan_list_(), static_route_list_(), allowed_address_pair_list_(), vrf_assign_rule_list_(), - vrf_assign_acl_(NULL) { + vrf_assign_acl_(NULL), sub_type_(VmInterface::NONE), configurer_(0), + ifmap_node_(NULL), subnet_(0), subnet_plen_(0) { ipv4_active_ = false; ipv6_active_ = false; l2_active_ = false; @@ -267,14 +271,31 @@ static void BuildStaticRouteList(VmInterfaceConfigData *data, IFMapNode *node) { LOG(DEBUG, "Error decoding v4 Static Route address " << it->prefix); } } + + IpAddress gw = IpAddress::from_string(it->next_hop, ec); + if (ec) { + gw = IpAddress::from_string("0.0.0.0", ec); + } if (add) { data->static_route_list_.list_.insert - (VmInterface::StaticRoute(data->vrf_name_, ip, plen)); - + (VmInterface::StaticRoute(data->vrf_name_, ip, plen, gw)); } } } +static void BuildResolveRoute(VmInterfaceConfigData *data, IFMapNode *node) { + Subnet *entry = + static_cast(node->GetObject()); + assert(entry); + Ip4Address ip; + boost::system::error_code ec; + ip = Ip4Address::from_string(entry->ip_prefix().ip_prefix, ec); + if (ec.value() == 0) { + data->subnet_ = ip; + data->subnet_plen_ = entry->ip_prefix().ip_prefix_len; + } +} + static void BuildAllowedAddressPairRouteList(VirtualMachineInterface *cfg, VmInterfaceConfigData *data) { for (std::vector::const_iterator it = @@ -484,6 +505,55 @@ static void ReadDhcpEnable(Agent *agent, VmInterfaceConfigData *data, } } +//TBD Use link instead of device_owner +VmInterface::SubType GetVmInterfaceSubType(Agent *agent, + const std::string &device_owner) { + if (device_owner.compare("compute:nova") == 0 || agent->test_mode() || + agent->tsn_enabled() == false) + return VmInterface::NOVA; + else + return VmInterface::TOR; +} + +void VmInterface::SetConfigurer(VmInterface::Configurer type) { + configurer_ |= (1 << type); +} + +void VmInterface::ResetConfigurer(VmInterface::Configurer type) { + configurer_ &= ~(1 << type); +} + +bool VmInterface::IsConfigurerSet(VmInterface::Configurer type) { + return ((configurer_ & (1 << type)) != 0); +} + +static bool +AddPhysicalInterface(Agent *agent, IFMapNode *node) { + bool ret = false; + + IFMapNode *physical_node = agent->cfg_listener()-> + FindAdjacentIFMapNode(agent, node, "physical-router"); + if (!physical_node) { + return ret; + } + + autogen::PhysicalRouter *physical_router = + static_cast (physical_node->GetObject()); + if (physical_router->display_name() == agent->host_name()) { + autogen::PhysicalInterface *physical_interface = + static_cast (node->GetObject()); + InterfaceTable *intf_table = agent->interface_table(); + ::PhysicalInterface::Create(intf_table, + physical_interface->display_name(), + agent->fabric_vrf_name(), + ::PhysicalInterface::FABRIC, ::PhysicalInterface::ETHERNET, + false); + ret = true; + } + + return ret; +} + // Virtual Machine Interface is added or deleted into oper DB from Nova // messages. The Config notify is used only to change interface. bool InterfaceTable::IFNodeToReq(IFMapNode *node, DBRequest &req) { @@ -495,36 +565,39 @@ bool InterfaceTable::IFNodeToReq(IFMapNode *node, DBRequest &req) { boost::uuids::uuid u; CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong, u); - CfgIntTable *cfg_table = agent_->interface_config_table(); - CfgIntKey cfg_key(u); - CfgIntEntry *nova_entry = static_cast - (cfg_table->Find(&cfg_key)); - // If interface is not yet added to Config tree, return. - // This API is invoked again when the interface is added to config tree. - if (!nova_entry) { - return false; - } - - // Skip, if Nova has deleted the interface - if (nova_entry->IsDeleted()) { - return false; - } + VmInterface::SubType interface_sub_type = + GetVmInterfaceSubType(agent_, cfg->device_owner()); // Skip config interface delete notification if (node->IsDeleted()) { - req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; - req.key.reset(new VmInterfaceKey(AgentKey::RESYNC, u, "")); - req.data.reset(new VmInterfaceConfigData()); - return true; + if (interface_sub_type == VmInterface::NOVA) { + req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; + req.key.reset(new VmInterfaceKey(AgentKey::RESYNC, u, "")); + req.data.reset(new VmInterfaceConfigData()); + return true; + } else { + VmInterface::Delete(this, u, VmInterface::CONFIG); + return false; + } } + CfgIntTable *cfg_table = agent_->interface_config_table(); + CfgIntKey cfg_key(u); + CfgIntEntry *cfg_entry = + static_cast (cfg_table->Find(&cfg_key)); + // Update interface configuration req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; - InterfaceKey *key = new VmInterfaceKey(AgentKey::RESYNC, u, ""); - - VmInterfaceConfigData *data; - data = new VmInterfaceConfigData(); + InterfaceKey *key = NULL; + if (interface_sub_type == VmInterface::NOVA) { + key = new VmInterfaceKey(AgentKey::RESYNC, u, ""); + } else { + key = new VmInterfaceKey(AgentKey::ADD_DEL_CHANGE, u, + cfg->display_name()); + } + VmInterfaceConfigData *data = new VmInterfaceConfigData(); + data->ifmap_node_ = node; //Extract the local preference if (cfg->IsPropertySet(VirtualMachineInterface::PROPERTIES)) { autogen::VirtualMachineInterfacePropertiesType prop = cfg->properties(); @@ -540,7 +613,7 @@ bool InterfaceTable::IFNodeToReq(IFMapNode *node, DBRequest &req) { ReadDhcpOptions(cfg, *data); //Fill config data items - data->cfg_name_= node->name(); + data->cfg_name_ = node->name(); data->admin_state_ = id_perms.enable; BuildVrfAssignRule(cfg, data); @@ -548,6 +621,7 @@ bool InterfaceTable::IFNodeToReq(IFMapNode *node, DBRequest &req) { SgUuidList sg_list(0); IFMapNode *vn_node = NULL; + // Walk Interface Graph to get VM, VN and FloatingIPList IFMapAgentTable *table = static_cast(node->table()); for (DBGraphVertex::adjacency_iterator iter = @@ -583,14 +657,14 @@ bool InterfaceTable::IFNodeToReq(IFMapNode *node, DBRequest &req) { autogen::IdPermsType id_perms = vn->id_perms(); CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong, data->vn_uuid_); - if (nova_entry->GetVnUuid() != data->vn_uuid_) { + if (cfg_entry && (cfg_entry->GetVnUuid() != data->vn_uuid_)) { IFMAP_ERROR(InterfaceConfiguration, "Virtual-network UUID mismatch for interface:", UuidToString(u), "configuration VN uuid", UuidToString(data->vn_uuid_), "compute VN uuid", - UuidToString(nova_entry->GetVnUuid())); + UuidToString(cfg_entry->GetVnUuid())); } } @@ -598,17 +672,24 @@ bool InterfaceTable::IFNodeToReq(IFMapNode *node, DBRequest &req) { VirtualMachine *vm = static_cast (adj_node->GetObject()); assert(vm); + + //VM link to virtual-router tells kind of virtual-router. + //If virtual-router is not of type TOR/TSN, then NOVA is the only + //place from where interface gets created. So if subtype is unknown + //and there was a nova entry found then treat it as NOVA else + //ignore the request. Subsequent addition of VM or nova should + //re-invoke this routine. autogen::IdPermsType id_perms = vm->id_perms(); CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong, data->vm_uuid_); - if (nova_entry->GetVmUuid() != data->vm_uuid_) { + if (cfg_entry && (cfg_entry->GetVmUuid() != data->vm_uuid_)) { IFMAP_ERROR(InterfaceConfiguration, "Virtual-machine UUID mismatch for interface:", UuidToString(u), "configuration VM UUID is", UuidToString(data->vm_uuid_), "compute VM uuid is", - UuidToString(nova_entry->GetVnUuid())); + UuidToString(cfg_entry->GetVnUuid())); } } @@ -627,6 +708,41 @@ bool InterfaceTable::IFNodeToReq(IFMapNode *node, DBRequest &req) { if (adj_node->table() == agent_->cfg()->cfg_route_table()) { BuildStaticRouteList(data, adj_node); } + + if (adj_node->table() == agent_->cfg()->cfg_subnet_table()) { + BuildResolveRoute(data, adj_node); + } + } + + //Read parent interface name if any + IFMapNode *logical_node = agent_->cfg_listener()-> + FindAdjacentIFMapNode(agent_, node, + "logical-interface"); + if (logical_node) { + IFMapNode *physical_node = agent_->cfg_listener()-> + FindAdjacentIFMapNode(agent_, logical_node, "physical-interface"); + //Add physical interface + if (physical_node && AddPhysicalInterface(agent_, physical_node)) { + autogen::PhysicalInterface *physical_interface = + static_cast ( + physical_node->GetObject()); + data->parent_ = physical_interface->display_name(); + } + } + + if (!data->subnet_.is_unspecified() && + data->parent_ != agent_->NullString()) { + interface_sub_type = VmInterface::VCPE; + delete key; + //Add request for a VMI of type VCPE + key = new VmInterfaceKey(AgentKey::ADD_DEL_CHANGE, u, + cfg->display_name()); + } + + data->sub_type_ = interface_sub_type; + + if (cfg->mac_addresses().size()) { + data->vm_mac_ = cfg->mac_addresses().at(0); } // Get DHCP enable flag from subnet @@ -692,28 +808,11 @@ Interface *VmInterfaceKey::AllocEntry(const InterfaceTable *table) const { Interface *VmInterfaceKey::AllocEntry(const InterfaceTable *table, const InterfaceData *data) const { - const VmInterfaceAddData *vm_data = - static_cast(data); - // Add is only supported with ADD_DEL_CHANGE key and data - assert(vm_data->type_ == VmInterfaceData::ADD_DEL_CHANGE); - - const VmInterfaceAddData *add_data = - static_cast(data); + const VmInterfaceData *vm_data = + static_cast(data); - Interface *parent = NULL; - if (add_data->tx_vlan_id_ != VmInterface::kInvalidVlanId && - add_data->rx_vlan_id_ != VmInterface::kInvalidVlanId && - add_data->parent_ != Agent::NullString()) { - PhysicalInterfaceKey key(add_data->parent_); - parent = static_cast - (table->agent()->interface_table()->FindActiveEntry(&key)); - assert(parent != NULL); - } - - return new VmInterface(uuid_, name_, add_data->ip_addr_, add_data->vm_mac_, - add_data->vm_name_, add_data->vm_project_uuid_, - add_data->tx_vlan_id_, add_data->rx_vlan_id_, - parent, add_data->ip6_addr_); + VmInterface *vmi = vm_data->OnAdd(table, this); + return vmi; } InterfaceKey *VmInterfaceKey::Clone() const { @@ -738,14 +837,16 @@ const Peer *VmInterface::peer() const { } bool VmInterface::OnChange(VmInterfaceData *data) { - return false; + InterfaceTable *table = static_cast(get_table()); + return Resync(table, data); } // Handle RESYNC DB Request. Handles multiple sub-types, // - CONFIG : RESYNC from config message // - IP_ADDR: RESYNC due to learning IP from DHCP // - MIRROR : RESYNC due to change in mirror config -bool VmInterface::Resync(VmInterfaceData *data) { +bool VmInterface::Resync(const InterfaceTable *table, + const VmInterfaceData *data) { bool ret = false; // Copy old values used to update config below @@ -761,28 +862,12 @@ bool VmInterface::Resync(VmInterfaceData *data) { bool sg_changed = false; bool ecmp_changed = false; bool local_pref_changed = false; + Ip4Address old_subnet = subnet_; + uint8_t old_subnet_plen = subnet_plen_; if (data) { - if (data->type_ == VmInterfaceData::CONFIG) { - VmInterfaceConfigData *cfg = static_cast - (data); - ret = CopyConfig(cfg, &sg_changed, &ecmp_changed, - &local_pref_changed); - } else if (data->type_ == VmInterfaceData::IP_ADDR) { - VmInterfaceIpAddressData *addr = - static_cast (data); - ret = ResyncIpAddress(addr); - } else if (data->type_ == VmInterfaceData::MIRROR) { - VmInterfaceMirrorData *mirror = static_cast - (data); - ret = ResyncMirror(mirror); - } else if (data->type_ == VmInterfaceData::OS_OPER_STATE) { - VmInterfaceOsOperStateData *oper_state = - static_cast (data); - ret = ResyncOsOperState(oper_state); - } else { - assert(0); - } + ret = data->OnResync(table, this, &sg_changed, &ecmp_changed, + &local_pref_changed); } ipv4_active_ = IsIpv4Active(); @@ -809,7 +894,7 @@ bool VmInterface::Resync(VmInterfaceData *data) { ApplyConfig(old_ipv4_active, old_l2_active, old_policy, old_vrf.get(), old_addr, old_vxlan_id, old_need_linklocal_ip, sg_changed, old_ipv6_active, old_v6_addr, ecmp_changed, - local_pref_changed); + local_pref_changed, old_subnet, old_subnet_plen); return ret; } @@ -818,11 +903,177 @@ void VmInterface::Add() { peer_.reset(new LocalVmPortPeer(LOCAL_VM_PORT_PEER_NAME, id_)); } -void VmInterface::Delete() { - VmInterfaceConfigData data; - Resync(&data); +bool VmInterface::Delete(const DBRequest *req) { InterfaceTable *table = static_cast(get_table()); + const VmInterfaceData *vm_data = static_cast + (req->data.get()); + vm_data->OnDelete(table, this); + if (configurer_) { + return false; + } table->DeleteDhcpSnoopEntry(name_); + return true; +} + +void VmInterface::UpdateL3(bool old_ipv4_active, VrfEntry *old_vrf, + const Ip4Address &old_addr, int old_vxlan_id, + bool force_update, bool policy_change, + bool old_ipv6_active, + const Ip6Address &old_v6_addr, + const Ip4Address &old_subnet, + const uint8_t old_subnet_plen) { + UpdateSecurityGroup(); + UpdateL3NextHop(old_ipv4_active, old_ipv6_active); + UpdateL3TunnelId(force_update, policy_change); + if (ipv4_active_) { + UpdateIpv4InterfaceRoute(old_ipv4_active, force_update, policy_change, + old_vrf, old_addr); + UpdateMetadataRoute(old_ipv4_active, old_vrf); + UpdateFloatingIp(force_update, policy_change); + UpdateServiceVlan(force_update, policy_change); + UpdateAllowedAddressPair(force_update, policy_change); + UpdateVrfAssignRule(); + UpdateResolveRoute(old_ipv4_active, force_update, policy_change, + old_vrf, old_subnet, old_subnet_plen); + } + if (ipv6_active_) { + UpdateIpv6InterfaceRoute(old_ipv6_active, force_update, policy_change, + old_vrf, old_v6_addr); + } + UpdateStaticRoute(force_update, policy_change); +} + +void VmInterface::DeleteL3(bool old_ipv4_active, VrfEntry *old_vrf, + const Ip4Address &old_addr, + bool old_need_linklocal_ip, bool old_ipv6_active, + const Ip6Address &old_v6_addr, + const Ip4Address &old_subnet, + const uint8_t old_subnet_plen) { + if (old_ipv4_active) { + DeleteIpv4InterfaceRoute(old_vrf, old_addr); + } + if (old_ipv6_active) { + DeleteIpv6InterfaceRoute(old_vrf, old_v6_addr); + } + DeleteMetadataRoute(old_ipv4_active, old_vrf, old_need_linklocal_ip); + DeleteFloatingIp(); + DeleteServiceVlan(); + DeleteStaticRoute(); + DeleteAllowedAddressPair(); + DeleteSecurityGroup(); + DeleteL3TunnelId(); + DeleteVrfAssignRule(); + DeleteL3NextHop(old_ipv4_active, old_ipv6_active); + DeleteResolveRoute(old_vrf, old_subnet, old_subnet_plen); +} + +void VmInterface::UpdateVxLan() { + int new_vxlan_id = vn_.get() ? vn_->GetVxLanId() : 0; + if (l2_active_ && ((vxlan_id_ == 0) || + (vxlan_id_ != new_vxlan_id))) { + vxlan_id_ = new_vxlan_id; + } +} + +void VmInterface::UpdateL2(bool old_l2_active, VrfEntry *old_vrf, int old_vxlan_id, + bool force_update, bool policy_change) { + UpdateVxLan(); + UpdateL2NextHop(old_l2_active); + //Update label only if new entry is to be created, so + //no force update on same. + UpdateL2TunnelId(false, policy_change); + UpdateL2InterfaceRoute(old_l2_active, force_update); +} + +void VmInterface::UpdateL2(bool force_update) { + UpdateL2(l2_active_, vrf_.get(), vxlan_id_, force_update, false); +} + +void VmInterface::DeleteL2(bool old_l2_active, VrfEntry *old_vrf) { + DeleteL2TunnelId(); + DeleteL2InterfaceRoute(old_l2_active, old_vrf); + DeleteL2NextHop(old_l2_active); +} + +// Apply the latest configuration +void VmInterface::ApplyConfig(bool old_ipv4_active, bool old_l2_active, bool old_policy, + VrfEntry *old_vrf, const Ip4Address &old_addr, + int old_vxlan_id, bool old_need_linklocal_ip, + bool sg_changed, bool old_ipv6_active, + const Ip6Address &old_v6_addr, bool ecmp_mode_changed, + bool local_pref_changed, + const Ip4Address &old_subnet, + uint8_t old_subnet_plen) { + //Need not apply config for TOR VMI as it is more of an inidicative + //interface. No route addition or NH addition happens for this interface. + if (sub_type_ == VmInterface::TOR && + (old_subnet.is_unspecified() && old_subnet_plen == 0)) { + return; + } + + bool force_update = false; + if (sg_changed || ecmp_mode_changed | local_pref_changed) { + force_update = true; + } + + bool policy_change = (policy_enabled_ != old_policy); + + if (ipv4_active_ == true || l2_active_ == true) { + UpdateMulticastNextHop(old_ipv4_active, old_l2_active); + } else { + DeleteMulticastNextHop(); + } + + //Irrespective of interface state, if ipv4 forwarding mode is enabled + //enable L3 services on this interface + if (layer3_forwarding_) { + UpdateL3Services(dhcp_enable_, true); + } else { + UpdateL3Services(false, false); + } + + // Add/Del/Update L3 + if ((ipv4_active_ || ipv6_active_) && layer3_forwarding_) { + UpdateL3(old_ipv4_active, old_vrf, old_addr, old_vxlan_id, force_update, + policy_change, old_ipv6_active, old_v6_addr, + old_subnet, old_subnet_plen); + } else if ((old_ipv4_active || old_ipv6_active)) { + DeleteL3(old_ipv4_active, old_vrf, old_addr, old_need_linklocal_ip, + old_ipv6_active, old_v6_addr, + old_subnet, old_subnet_plen); + } + + // Add/Del/Update L2 + if (l2_active_ && layer2_forwarding_) { + UpdateL2(old_l2_active, old_vrf, old_vxlan_id, + force_update, policy_change); + } else if (old_l2_active) { + DeleteL2(old_l2_active, old_vrf); + } + + if (old_l2_active != l2_active_) { + if (l2_active_) { + SendTrace(ACTIVATED_L2); + } else { + SendTrace(DEACTIVATED_L2); + } + } + + if (old_ipv4_active != ipv4_active_) { + if (ipv4_active_) { + SendTrace(ACTIVATED_IPV4); + } else { + SendTrace(DEACTIVATED_IPV4); + } + } + + if (old_ipv6_active != ipv6_active_) { + if (ipv6_active_) { + SendTrace(ACTIVATED_IPV6); + } else { + SendTrace(DEACTIVATED_IPV6); + } + } } bool VmInterface::CopyIpAddress(Ip4Address &addr) { @@ -854,30 +1105,65 @@ bool VmInterface::CopyIpAddress(Ip4Address &addr) { return ret; } +///////////////////////////////////////////////////////////////////////////// +// VmInterfaceConfigData routines +///////////////////////////////////////////////////////////////////////////// +VmInterface *VmInterfaceConfigData::OnAdd(const InterfaceTable *table, + const VmInterfaceKey *key) const { + VmInterface *vmi = + new VmInterface(key->uuid_, key->name_, addr_, vm_mac_, vm_name_, + vm_uuid_, VmInterface::kInvalidVlanId, + VmInterface::kInvalidVlanId, NULL, ip6_addr_); + vmi->SetConfigurer(VmInterface::CONFIG); + return vmi; +} + +bool VmInterfaceConfigData::OnDelete(const InterfaceTable *table, + VmInterface *vmi) const { + if (vmi->IsConfigurerSet(VmInterface::CONFIG) == false) + return true; + + vmi->ResetConfigurer(VmInterface::CONFIG); + VmInterfaceConfigData data; + vmi->Resync(table, &data); + if (ifmap_node_ != NULL) + table->operdb()->dependency_manager()->ResetObject(ifmap_node_); + return true; +} + +bool VmInterfaceConfigData::OnResync(const InterfaceTable *table, + VmInterface *vmi, bool *sg_changed, + bool *ecmp_changed, + bool *local_pref_changed) const { + return vmi->CopyConfig(table, this, sg_changed, ecmp_changed, + local_pref_changed); +} + // Copies configuration from DB-Request data. The actual applying of // configuration, like adding/deleting routes must be done with ApplyConfig() -bool VmInterface::CopyConfig(VmInterfaceConfigData *data, bool *sg_changed, +bool VmInterface::CopyConfig(const InterfaceTable *table, + const VmInterfaceConfigData *data, + bool *sg_changed, bool *ecmp_changed, bool *local_pref_changed) { bool ret = false; - InterfaceTable *table = static_cast(get_table()); - - - VmEntry *vm = table->FindVmRef(data->vm_uuid_); - if (vm_.get() != vm) { - vm_ = vm; - ret = true; - } + if (table) { + VmEntry *vm = table->FindVmRef(data->vm_uuid_); + if (vm_.get() != vm) { + vm_ = vm; + ret = true; + } - VrfEntry *vrf = table->FindVrfRef(data->vrf_name_); - if (vrf_.get() != vrf) { - vrf_ = vrf; - ret = true; - } + VrfEntry *vrf = table->FindVrfRef(data->vrf_name_); + if (vrf_.get() != vrf) { + vrf_ = vrf; + ret = true; + } - MirrorEntry *mirror = table->FindMirrorRef(data->analyzer_name_); - if (mirror_entry_.get() != mirror) { - mirror_entry_ = mirror; - ret = true; + MirrorEntry *mirror = table->FindMirrorRef(data->analyzer_name_); + if (mirror_entry_.get() != mirror) { + mirror_entry_ = mirror; + ret = true; + } } MirrorDirection mirror_direction = data->mirror_direction_; @@ -893,22 +1179,24 @@ bool VmInterface::CopyConfig(VmInterfaceConfigData *data, bool *sg_changed, } // Read ifindex for the interface - if (os_index_ == kInvalidIndex) { - GetOsParams(table->agent()); - if (os_index_ != kInvalidIndex) - ret = true; - } + if (table) { + if (os_index_ == kInvalidIndex) { + GetOsParams(table->agent()); + if (os_index_ != kInvalidIndex) + ret = true; + } - VnEntry *vn = table->FindVnRef(data->vn_uuid_); - if (vn_.get() != vn) { - vn_ = vn; - ret = true; - } + VnEntry *vn = table->FindVnRef(data->vn_uuid_); + if (vn_.get() != vn) { + vn_ = vn; + ret = true; + } - int vxlan_id = vn ? vn->GetVxLanId() : 0; - if (vxlan_id_ != vxlan_id) { - vxlan_id_ = vxlan_id; - ret = true; + int vxlan_id = vn ? vn->GetVxLanId() : 0; + if (vxlan_id_ != vxlan_id) { + vxlan_id_ = vxlan_id; + ret = true; + } } if (local_preference_ != data->local_preference_) { @@ -917,19 +1205,7 @@ bool VmInterface::CopyConfig(VmInterfaceConfigData *data, bool *sg_changed, ret = true; } - bool val = vn ? vn_->layer2_forwarding() : false; - if (layer2_forwarding_ != val) { - layer2_forwarding_ = val; - ret = true; - } - - val = vn ? vn_->layer3_forwarding() : false; - if (layer3_forwarding_ != val) { - layer3_forwarding_ = val; - ret = true; - } - - val = layer3_forwarding_ ? data->need_linklocal_ip_ : false; + bool val = layer3_forwarding_ ? data->need_linklocal_ip_ : false; if (need_linklocal_ip_ != val) { need_linklocal_ip_ = val; ret = true; @@ -971,12 +1247,17 @@ bool VmInterface::CopyConfig(VmInterfaceConfigData *data, bool *sg_changed, ret = true; } + if (subnet_ != data->subnet_ || subnet_plen_ != data->subnet_plen_) { + subnet_ = data->subnet_; + subnet_plen_ = data->subnet_plen_; + } + // Copy DHCP options; ret is not modified as there is no dependent action oper_dhcp_options_ = data->oper_dhcp_options_; // Audit operational and config floating-ip list FloatingIpSet &old_fip_list = floating_ip_list_.list_; - FloatingIpSet &new_fip_list = data->floating_ip_list_.list_; + const FloatingIpSet &new_fip_list = data->floating_ip_list_.list_; if (AuditList (floating_ip_list_, old_fip_list.begin(), old_fip_list.end(), new_fip_list.begin(), new_fip_list.end())) { @@ -987,7 +1268,7 @@ bool VmInterface::CopyConfig(VmInterfaceConfigData *data, bool *sg_changed, // Audit operational and config Service VLAN list ServiceVlanSet &old_service_list = service_vlan_list_.list_; - ServiceVlanSet &new_service_list = data->service_vlan_list_.list_; + const ServiceVlanSet &new_service_list = data->service_vlan_list_.list_; if (AuditList (service_vlan_list_, old_service_list.begin(), old_service_list.end(), new_service_list.begin(), new_service_list.end())) { @@ -996,7 +1277,7 @@ bool VmInterface::CopyConfig(VmInterfaceConfigData *data, bool *sg_changed, // Audit operational and config Static Route list StaticRouteSet &old_route_list = static_route_list_.list_; - StaticRouteSet &new_route_list = data->static_route_list_.list_; + const StaticRouteSet &new_route_list = data->static_route_list_.list_; if (AuditList (static_route_list_, old_route_list.begin(), old_route_list.end(), new_route_list.begin(), new_route_list.end())) { @@ -1005,7 +1286,8 @@ bool VmInterface::CopyConfig(VmInterfaceConfigData *data, bool *sg_changed, // Audit operational and config allowed address pair AllowedAddressPairSet &old_aap_list = allowed_address_pair_list_.list_; - AllowedAddressPairSet &new_aap_list = data->allowed_address_pair_list_.list_; + const AllowedAddressPairSet &new_aap_list = data-> + allowed_address_pair_list_.list_; if (AuditList (allowed_address_pair_list_, old_aap_list.begin(), old_aap_list.end(), new_aap_list.begin(), new_aap_list.end())) { @@ -1014,260 +1296,253 @@ bool VmInterface::CopyConfig(VmInterfaceConfigData *data, bool *sg_changed, // Audit operational and config Security Group list SecurityGroupEntrySet &old_sg_list = sg_list_.list_; - SecurityGroupEntrySet &new_sg_list = data->sg_list_.list_; + const SecurityGroupEntrySet &new_sg_list = data->sg_list_.list_; *sg_changed = - AuditList - (sg_list_, old_sg_list.begin(), old_sg_list.end(), - new_sg_list.begin(), new_sg_list.end()); - if (*sg_changed) { - ret = true; - } - - VrfAssignRuleSet &old_vrf_assign_list = vrf_assign_rule_list_.list_; - VrfAssignRuleSet &new_vrf_assign_list = data->vrf_assign_rule_list_.list_; - if (AuditList - (vrf_assign_rule_list_, old_vrf_assign_list.begin(), - old_vrf_assign_list.end(), new_vrf_assign_list.begin(), - new_vrf_assign_list.end())) { - ret = true; - } - - if (data->addr_ != Ip4Address(0) && ecmp_ != data->ecmp_) { - ecmp_ = data->ecmp_; - *ecmp_changed = true; - } - return ret; -} - -void VmInterface::UpdateL3(bool old_ipv4_active, VrfEntry *old_vrf, - const Ip4Address &old_addr, int old_vxlan_id, - bool force_update, bool policy_change, - bool old_ipv6_active, - const Ip6Address &old_v6_addr) { - UpdateSecurityGroup(); - UpdateL3NextHop(old_ipv4_active, old_ipv6_active); - UpdateL3TunnelId(force_update, policy_change); - if (ipv4_active_) { - UpdateIpv4InterfaceRoute(old_ipv4_active, force_update, policy_change, - old_vrf, old_addr); - UpdateMetadataRoute(old_ipv4_active, old_vrf); - UpdateFloatingIp(force_update, policy_change); - UpdateServiceVlan(force_update, policy_change); - UpdateAllowedAddressPair(force_update, policy_change); - UpdateVrfAssignRule(); - } - if (ipv6_active_) { - UpdateIpv6InterfaceRoute(old_ipv6_active, force_update, policy_change, - old_vrf, old_v6_addr); - } - UpdateStaticRoute(force_update, policy_change); -} - -void VmInterface::DeleteL3(bool old_ipv4_active, VrfEntry *old_vrf, - const Ip4Address &old_addr, - bool old_need_linklocal_ip, bool old_ipv6_active, - const Ip6Address &old_v6_addr) { - if (old_ipv4_active) { - DeleteIpv4InterfaceRoute(old_vrf, old_addr); - } - if (old_ipv6_active) { - DeleteIpv6InterfaceRoute(old_vrf, old_v6_addr); - } - DeleteMetadataRoute(old_ipv4_active, old_vrf, old_need_linklocal_ip); - DeleteFloatingIp(); - DeleteServiceVlan(); - DeleteStaticRoute(); - DeleteAllowedAddressPair(); - DeleteSecurityGroup(); - DeleteL3TunnelId(); - DeleteVrfAssignRule(); - DeleteL3NextHop(old_ipv4_active, old_ipv6_active); -} - -void VmInterface::UpdateVxLan() { - int new_vxlan_id = vn_.get() ? vn_->GetVxLanId() : 0; - if (l2_active_ && ((vxlan_id_ == 0) || - (vxlan_id_ != new_vxlan_id))) { - vxlan_id_ = new_vxlan_id; - } -} - -void VmInterface::UpdateL2(bool old_l2_active, VrfEntry *old_vrf, int old_vxlan_id, - bool force_update, bool policy_change) { - UpdateVxLan(); - UpdateL2NextHop(old_l2_active); - //Update label only if new entry is to be created, so - //no force update on same. - UpdateL2TunnelId(false, policy_change); - UpdateL2InterfaceRoute(old_l2_active, force_update); -} - -void VmInterface::UpdateL2(bool force_update) { - UpdateL2(l2_active_, vrf_.get(), vxlan_id_, force_update, false); -} - -void VmInterface::DeleteL2(bool old_l2_active, VrfEntry *old_vrf) { - DeleteL2TunnelId(); - DeleteL2InterfaceRoute(old_l2_active, old_vrf); - DeleteL2NextHop(old_l2_active); -} - -// Apply the latest configuration -void VmInterface::ApplyConfig(bool old_ipv4_active, bool old_l2_active, bool old_policy, - VrfEntry *old_vrf, const Ip4Address &old_addr, - int old_vxlan_id, bool old_need_linklocal_ip, - bool sg_changed, bool old_ipv6_active, - const Ip6Address &old_v6_addr, bool ecmp_mode_changed, - bool local_pref_changed) { - bool force_update = false; - if (sg_changed || ecmp_mode_changed | local_pref_changed) { - force_update = true; + AuditList + (sg_list_, old_sg_list.begin(), old_sg_list.end(), + new_sg_list.begin(), new_sg_list.end()); + if (*sg_changed) { + ret = true; } - bool policy_change = (policy_enabled_ != old_policy); + VrfAssignRuleSet &old_vrf_assign_list = vrf_assign_rule_list_.list_; + const VrfAssignRuleSet &new_vrf_assign_list = data-> + vrf_assign_rule_list_.list_; + if (AuditList + (vrf_assign_rule_list_, old_vrf_assign_list.begin(), + old_vrf_assign_list.end(), new_vrf_assign_list.begin(), + new_vrf_assign_list.end())) { + ret = true; + } - if (ipv4_active_ == true || l2_active_ == true) { - UpdateMulticastNextHop(old_ipv4_active, old_l2_active); - } else { - DeleteMulticastNextHop(); + if (data->addr_ != Ip4Address(0) && ecmp_ != data->ecmp_) { + ecmp_ = data->ecmp_; + *ecmp_changed = true; } - //Irrespective of interface state, if ipv4 forwarding mode is enabled - //enable L3 services on this interface - if (layer3_forwarding_) { - UpdateL3Services(dhcp_enable_, true); - } else { - UpdateL3Services(false, false); + if (sub_type_ != data->sub_type_) { + sub_type_= data->sub_type_; + ret = true; } - // Add/Del/Update L3 - if ((ipv4_active_ || ipv6_active_) && layer3_forwarding_) { - UpdateL3(old_ipv4_active, old_vrf, old_addr, old_vxlan_id, force_update, - policy_change, old_ipv6_active, old_v6_addr); - } else if ((old_ipv4_active || old_ipv6_active)) { - DeleteL3(old_ipv4_active, old_vrf, old_addr, old_need_linklocal_ip, - old_ipv6_active, old_v6_addr); + if (sub_type_ == VCPE) { + rx_vlan_id_ = data->rx_vlan_id_; + tx_vlan_id_ = data->tx_vlan_id_; } - // Add/Del/Update L2 - if (l2_active_ && layer2_forwarding_) { - UpdateL2(old_l2_active, old_vrf, old_vxlan_id, - force_update, policy_change); - } else if (old_l2_active) { - DeleteL2(old_l2_active, old_vrf); + if (data->parent_ != Agent::NullString()) { + PhysicalInterfaceKey key(data->parent_); + parent_ = static_cast + (table->agent()->interface_table()->FindActiveEntry(&key)); + assert(parent_ != NULL); } - if (old_l2_active != l2_active_) { - if (l2_active_) { - SendTrace(ACTIVATED_L2); - } else { - SendTrace(DEACTIVATED_L2); - } + if (ifmap_node_ != data->ifmap_node_) { + if (ifmap_node_ != NULL) + table->operdb()->dependency_manager()->ResetObject(ifmap_node_); + ifmap_node_ = data->ifmap_node_; + if (ifmap_node_) + table->operdb()->dependency_manager()->SetObject(ifmap_node_, this); } - if (old_ipv4_active != ipv4_active_) { - if (ipv4_active_) { - SendTrace(ACTIVATED_IPV4); - } else { - SendTrace(DEACTIVATED_IPV4); - } + return ret; +} + +///////////////////////////////////////////////////////////////////////////// +// VmInterfaceNovaData routines +///////////////////////////////////////////////////////////////////////////// +VmInterfaceNovaData::VmInterfaceNovaData() : + VmInterfaceData(NOVA), + ipv4_addr_(), + ipv6_addr_(), + mac_addr_(), + vm_name_(), + vm_uuid_(), + parent_(), + tx_vlan_id_(), + rx_vlan_id_() { +} + +VmInterfaceNovaData::VmInterfaceNovaData(const Ip4Address &ipv4_addr, + const Ip6Address &ipv6_addr, + const std::string &mac_addr, + const std::string vm_name, + boost::uuids::uuid vm_uuid, + const std::string &parent, + uint16_t tx_vlan_id, + uint16_t rx_vlan_id) : + VmInterfaceData(NOVA), + ipv4_addr_(ipv4_addr), + ipv6_addr_(ipv6_addr), + mac_addr_(mac_addr), + vm_name_(vm_name), + vm_uuid_(vm_uuid), + parent_(parent), + tx_vlan_id_(tx_vlan_id), + rx_vlan_id_(rx_vlan_id) { +} + +VmInterfaceNovaData::~VmInterfaceNovaData() { +} + +VmInterface *VmInterfaceNovaData::OnAdd(const InterfaceTable *table, + const VmInterfaceKey *key) const { + Interface *parent = NULL; + if (tx_vlan_id_ != VmInterface::kInvalidVlanId && + rx_vlan_id_ != VmInterface::kInvalidVlanId && + parent_ != Agent::NullString()) { + PhysicalInterfaceKey key_1(parent_); + parent = static_cast + (table->agent()->interface_table()->FindActiveEntry(&key_1)); + assert(parent != NULL); } + VmInterface *vmi = + new VmInterface(key->uuid_, key->name_, ipv4_addr_, mac_addr_, vm_name_, + vm_uuid_, tx_vlan_id_, rx_vlan_id_, parent, ipv6_addr_); + vmi->SetConfigurer(VmInterface::EXTERNAL); + return vmi; +} - if (old_ipv6_active != ipv6_active_) { - if (ipv6_active_) { - SendTrace(ACTIVATED_IPV6); - } else { - SendTrace(DEACTIVATED_IPV6); - } +bool VmInterfaceNovaData::OnDelete(const InterfaceTable *table, + VmInterface *vmi) const { + if (vmi->IsConfigurerSet(VmInterface::EXTERNAL) == false) + return true; + + vmi->ResetConfigurer(VmInterface::CONFIG); + VmInterfaceConfigData data; + vmi->Resync(table, &data); + vmi->ResetConfigurer(VmInterface::EXTERNAL); + return true; +} + +bool VmInterfaceNovaData::OnResync(const InterfaceTable *table, + VmInterface *vmi, bool *sg_changed, + bool *ecmp_changed, + bool *local_pref_changed) const { + bool ret = false; + + if (vmi->tx_vlan_id_ != tx_vlan_id_) { + vmi->tx_vlan_id_ = tx_vlan_id_; + ret = true; + } + + if (vmi->rx_vlan_id_ != rx_vlan_id_) { + vmi->rx_vlan_id_ = rx_vlan_id_; + ret = true; } + vmi->SetConfigurer(VmInterface::EXTERNAL); + + return ret; } -// Handle RESYNC message from mirror -bool VmInterface::ResyncMirror(VmInterfaceMirrorData *data) { +///////////////////////////////////////////////////////////////////////////// +// VmInterfaceMirrorData routines +///////////////////////////////////////////////////////////////////////////// +bool VmInterfaceMirrorData::OnResync(const InterfaceTable *table, + VmInterface *vmi, bool *sg_changed, + bool *ecmp_changed, + bool *local_pref_changed) const { bool ret = false; - InterfaceTable *table = static_cast(get_table()); MirrorEntry *mirror_entry = NULL; - - if (data->mirror_enable_ == true) { - mirror_entry = table->FindMirrorRef(data->analyzer_name_); + if (mirror_enable_ == true) { + mirror_entry = table->FindMirrorRef(analyzer_name_); } - if (mirror_entry_ != mirror_entry) { - mirror_entry_ = mirror_entry; + if (vmi->mirror_entry_ != mirror_entry) { + vmi->mirror_entry_ = mirror_entry; ret = true; } return ret; } +///////////////////////////////////////////////////////////////////////////// +// VmInterfaceIpAddressData routines +///////////////////////////////////////////////////////////////////////////// // Update for VM IP address only // For interfaces in IP Fabric VRF, we send DHCP requests to external servers // if config doesnt provide an address. This address is updated here. -bool VmInterface::ResyncIpAddress(const VmInterfaceIpAddressData *data) { +bool VmInterfaceIpAddressData::OnResync(const InterfaceTable *table, + VmInterface *vmi, bool *sg_changed, + bool *ecmp_changed, + bool *local_pref_changed) const { bool ret = false; - if (os_index_ == kInvalidIndex) { - InterfaceTable *table = static_cast(get_table()); - GetOsParams(table->agent()); - if (os_index_ != kInvalidIndex) + if (vmi->os_index_ == VmInterface::kInvalidIndex) { + vmi->GetOsParams(table->agent()); + if (vmi->os_index_ != VmInterface::kInvalidIndex) ret = true; } - if (!layer3_forwarding_) { + // Ignore IP address change if L3 Forwarding not enabled + if (!vmi->layer3_forwarding_) { return ret; } - bool old_ipv4_active = ipv4_active_; - Ip4Address old_addr = ip_addr_; - Ip4Address addr = Ip4Address(0); - if (CopyIpAddress(addr)) { + if (vmi->CopyIpAddress(addr)) { ret = true; } - ipv4_active_ = IsIpv4Active(); - ApplyConfig(old_ipv4_active, l2_active_, policy_enabled_, vrf_.get(), old_addr, - vxlan_id_, need_linklocal_ip_, false, ipv6_active_, - ip6_addr_, false, false); return ret; } +///////////////////////////////////////////////////////////////////////////// +// VmInterfaceOsOperStateData routines +///////////////////////////////////////////////////////////////////////////// // Resync oper-state for the interface -bool VmInterface::ResyncOsOperState(const VmInterfaceOsOperStateData *data) { +bool VmInterfaceOsOperStateData::OnResync(const InterfaceTable *table, + VmInterface *vmi, bool *sg_changed, + bool *ecmp_changed, + bool *local_pref_changed) const { bool ret = false; - InterfaceTable *table = static_cast(get_table()); - - uint32_t old_os_index = os_index_; - bool old_ipv4_active = ipv4_active_; - bool old_ipv6_active = ipv6_active_; + uint32_t old_os_index = vmi->os_index_; + bool old_ipv4_active = vmi->ipv4_active_; + bool old_ipv6_active = vmi->ipv6_active_; - GetOsParams(table->agent()); - if (os_index_ != old_os_index) + vmi->GetOsParams(table->agent()); + if (vmi->os_index_ != old_os_index) ret = true; - ipv4_active_ = IsIpv4Active(); - if (ipv4_active_ != old_ipv4_active) + vmi->ipv4_active_ = vmi->IsIpv4Active(); + if (vmi->ipv4_active_ != old_ipv4_active) ret = true; - ipv6_active_ = IsIpv6Active(); - if (ipv6_active_ != old_ipv6_active) + vmi->ipv6_active_ = vmi->IsIpv6Active(); + if (vmi->ipv6_active_ != old_ipv6_active) ret = true; - ApplyConfig(old_ipv4_active, l2_active_, policy_enabled_, vrf_.get(), - ip_addr_, vxlan_id_, need_linklocal_ip_, false, - old_ipv6_active, ip6_addr_, false, false); return ret; } ///////////////////////////////////////////////////////////////////////////// // VM Port Entry utility routines ///////////////////////////////////////////////////////////////////////////// +// Does the VMInterface need a physical device to be present +bool VmInterface::NeedDevice() const { + bool ret = true; -void VmInterface::GetOsParams(Agent *agent) { - if (rx_vlan_id_ == VmInterface::kInvalidVlanId) { + if (sub_type_ == TOR) + ret = false; + + if (subnet_.is_unspecified() == false) { + ret = false; + } + + if (rx_vlan_id_ != VmInterface::kInvalidVlanId) { + ret = false; + } else { + // Sanity check. rx_vlan_id is set, make sure tx_vlan_id is also set assert(tx_vlan_id_ == VmInterface::kInvalidVlanId); + } + + return ret; +} + +void VmInterface::GetOsParams(Agent *agent) { + if (NeedDevice()) { Interface::GetOsParams(agent); return; } @@ -1279,7 +1554,7 @@ void VmInterface::GetOsParams(Agent *agent) { // A VM Interface is L3 active under following conditions, // - If interface is deleted, it is inactive -// - VM, VN, VRF are set +// - VN, VRF are set // - For non-VMWARE hypervisors, // The tap interface must be created. This is verified by os_index_ // - MAC address set for the interface @@ -1292,7 +1567,7 @@ bool VmInterface::IsActive() const { return false; } - if ((vn_.get() == NULL) || (vm_.get() == NULL) || (vrf_.get() == NULL)) { + if ((vn_.get() == NULL) || (vrf_.get() == NULL)) { return false; } @@ -1300,19 +1575,26 @@ bool VmInterface::IsActive() const { return false; } - if (rx_vlan_id_ != VmInterface::kInvalidVlanId) { - assert(tx_vlan_id_ != VmInterface::kInvalidVlanId); - return true; + if (NeedDevice() == false) { + return true; } - if (os_index_ == kInvalidIndex) + if (subnet_.is_unspecified() && os_index_ == kInvalidIndex) return false; return mac_set_; } bool VmInterface::IsIpv4Active() const { - if (!layer3_forwarding() || (ip_addr_.to_ulong() == 0)) { + if (!layer3_forwarding()) { + return false; + } + + if (subnet_.is_unspecified() && ip_addr_.to_ulong() == 0) { + return false; + } + + if (subnet_.is_unspecified() == false && parent_ == NULL) { return false; } @@ -1590,16 +1872,31 @@ void VmInterface::DeleteMulticastNextHop() { InterfaceNH::DeleteMulticastVmInterfaceNH(GetUuid()); } +Ip4Address VmInterface::GetGateway() const { + Ip4Address ip(0); + if (vn_.get() == NULL) { + return ip; + } + + const VnIpam *ipam = NULL; + if (subnet_.is_unspecified()) { + ipam = vn_->GetIpam(ip_addr_); + } else { + ipam = vn_->GetIpam(subnet_); + } + + if (ipam) { + ip = ipam->default_gw.to_v4(); + } + return ip; +} + // Add/Update route. Delete old route if VRF or address changed void VmInterface::UpdateIpv4InterfaceRoute(bool old_ipv4_active, bool force_update, bool policy_change, VrfEntry * old_vrf, const Ip4Address &old_addr) { - const VnIpam *ipam = vn_->GetIpam(ip_addr_); - Ip4Address ip(0); - if (ipam) { - ip = ipam->default_gw.to_v4(); - } + Ip4Address ip = GetGateway(); // If interface was already active earlier and there is no force_update or // policy_change, return @@ -1677,6 +1974,40 @@ void VmInterface::UpdateIpv6InterfaceRoute(bool old_ipv6_active, bool force_upda } } +void VmInterface::UpdateResolveRoute(bool old_ipv4_active, bool force_update, + bool policy_change, VrfEntry * old_vrf, + const Ip4Address &old_addr, + uint8_t old_plen) { + if (old_ipv4_active == true && force_update == false + && policy_change == false && old_addr == subnet_ && + subnet_plen_ == old_plen) { + return; + } + + if (old_vrf && (old_vrf != vrf_.get() || + old_addr != subnet_ || + subnet_plen_ != old_plen)) { + DeleteResolveRoute(old_vrf, old_addr, old_plen); + } + + if (subnet_.to_ulong() != 0 && vrf_.get() != NULL && vn_.get() != NULL) { + SecurityGroupList sg_id_list; + CopySgIdList(&sg_id_list); + VmInterfaceKey vm_intf_key(AgentKey::ADD_DEL_CHANGE, GetUuid(), ""); + + InetUnicastAgentRouteTable::AddResolveRoute(peer_.get(), vrf_->GetName(), + Address::GetIp4SubnetAddress(subnet_, subnet_plen_), + subnet_plen_, vm_intf_key, vn_->table_label(), + policy_enabled_, vn_->GetName(), sg_id_list); + } +} + +void VmInterface::DeleteResolveRoute(VrfEntry *old_vrf, + const Ip4Address &old_addr, + const uint8_t plen) { + DeleteRoute(old_vrf->GetName(), old_addr, plen); +} + void VmInterface::DeleteIpv4InterfaceRoute(VrfEntry *old_vrf, const Ip4Address &old_addr) { if ((old_vrf == NULL) || (old_addr.to_ulong() == 0)) @@ -2086,6 +2417,18 @@ void VmInterface::AddRoute(const std::string &vrf_name, const IpAddress &addr, return; } +void VmInterface::ResolveRoute(const std::string &vrf_name, const Ip4Address &addr, + uint32_t plen, const std::string &dest_vn, bool policy) { + SecurityGroupList sg_id_list; + CopySgIdList(&sg_id_list); + VmInterfaceKey vm_intf_key(AgentKey::ADD_DEL_CHANGE, GetUuid(), ""); + + InetUnicastAgentRouteTable::AddResolveRoute(peer_.get(), vrf_name, + Address::GetIp4SubnetAddress(addr, plen), + plen, vm_intf_key, vn_->table_label(), + policy, dest_vn, sg_id_list); +} + void VmInterface::DeleteRoute(const std::string &vrf_name, const IpAddress &addr, uint32_t plen) { InetUnicastAgentRouteTable::Delete(peer_.get(), vrf_name, addr, plen); @@ -2271,18 +2614,18 @@ void VmInterface::FloatingIpList::Remove(FloatingIpSet::iterator &it) { // StaticRoute routines ///////////////////////////////////////////////////////////////////////////// VmInterface::StaticRoute::StaticRoute() : - ListEntry(), vrf_(""), addr_(), plen_(0) { + ListEntry(), vrf_(""), addr_(), plen_(0), gw_() { } VmInterface::StaticRoute::StaticRoute(const StaticRoute &rhs) : ListEntry(rhs.installed_, rhs.del_pending_), vrf_(rhs.vrf_), - addr_(rhs.addr_), plen_(rhs.plen_) { + addr_(rhs.addr_), plen_(rhs.plen_), gw_(rhs.gw_) { } VmInterface::StaticRoute::StaticRoute(const std::string &vrf, const IpAddress &addr, - uint32_t plen) : - ListEntry(), vrf_(vrf), addr_(addr), plen_(plen) { + uint32_t plen, const IpAddress &gw) : + ListEntry(), vrf_(vrf), addr_(addr), plen_(plen), gw_(gw) { } VmInterface::StaticRoute::~StaticRoute() { @@ -2323,10 +2666,21 @@ void VmInterface::StaticRoute::Activate(VmInterface *interface, if (addr_.is_v4()) { ecmp = interface->ecmp(); } - interface->AddRoute(vrf_, addr_, plen_, - interface->vn_->GetName(), - interface->policy_enabled(), - ecmp, IpAddress()); + Ip4Address gw_ip(0); + if (gw_.is_v4() && addr_.is_v4() && gw_.to_v4() != gw_ip) { + SecurityGroupList sg_id_list; + interface->CopySgIdList(&sg_id_list); + InetUnicastAgentRouteTable::AddGatewayRoute(interface->peer_.get(), + vrf_, addr_.to_v4(), + plen_, gw_.to_v4(), interface->vn_->GetName(), + interface->vn_->table_label(), + sg_id_list); + } else { + interface->AddRoute(vrf_, addr_, plen_, + interface->vn_->GetName(), + interface->policy_enabled(), + ecmp, IpAddress()); + } } installed_ = true; @@ -2799,6 +3153,81 @@ void VmInterface::InstanceIpSync(InterfaceTable *table, IFMapNode *node) { } +void VmInterface::PhysicalPortSync(InterfaceTable *table, IFMapNode *node) { + CfgListener *cfg_listener = table->agent()->cfg_listener(); + if (cfg_listener->SkipNode(node)) { + return; + } + + DBGraph *graph = + static_cast (node->table())->GetGraph();; + for (DBGraphVertex::adjacency_iterator iter = node->begin(graph); + iter != node->end(graph); ++iter) { + IFMapNode *adj = static_cast(iter.operator->()); + if (table->agent()->cfg_listener()->SkipNode(adj)) { + continue; + } + + if (adj->table() == + table->agent()->cfg()->cfg_logical_port_table()) { + LogicalPortSync(table, adj); + } + } +} + + + +void VmInterface::LogicalPortSync(InterfaceTable *table, IFMapNode *node) { + CfgListener *cfg_listener = table->agent()->cfg_listener(); + if (cfg_listener->SkipNode(node)) { + return; + } + + DBGraph *graph = + static_cast (node->table())->GetGraph();; + for (DBGraphVertex::adjacency_iterator iter = node->begin(graph); + iter != node->end(graph); ++iter) { + IFMapNode *adj = static_cast(iter.operator->()); + if (table->agent()->cfg_listener()->SkipNode(adj)) { + continue; + } + + if (adj->table() == + table->agent()->cfg()->cfg_vm_interface_table()) { + DBRequest req; + if (table->IFNodeToReq(adj, req)) { + table->Enqueue(&req); + } + } + } +} + + +void VmInterface::SubnetSync(InterfaceTable *table, IFMapNode *node) { + CfgListener *cfg_listener = table->agent()->cfg_listener(); + if (cfg_listener->SkipNode(node)) { + return; + } + + DBGraph *graph = + static_cast (node->table())->GetGraph();; + for (DBGraphVertex::adjacency_iterator iter = node->begin(graph); + iter != node->end(graph); ++iter) { + IFMapNode *adj = static_cast(iter.operator->()); + if (table->agent()->cfg_listener()->SkipNode(adj)) { + continue; + } + + if (adj->table() == + table->agent()->cfg()->cfg_vm_interface_table()) { + DBRequest req; + if (table->IFNodeToReq(adj, req)) { + table->Enqueue(&req); + } + } + } +} + void VmInterface::FloatingIpVnSync(InterfaceTable *table, IFMapNode *node) { CfgListener *cfg_listener = table->agent()->cfg_listener(); if (cfg_listener->SkipNode(node)) { @@ -2860,6 +3289,34 @@ void VmInterface::VnSync(InterfaceTable *table, IFMapNode *node) { } } +//TBD replace it with ifmap dependancy manager +void VmInterface::VmSync(InterfaceTable *table, IFMapNode *node) { + CfgListener *cfg_listener = table->agent()->cfg_listener(); + if (cfg_listener->SkipNode(node)) { + return; + } + // Walk the node to get neighbouring interface + DBGraph *graph = + static_cast (node->table())->GetGraph(); + for (DBGraphVertex::adjacency_iterator iter = node->begin(graph); + iter != node->end(graph); ++iter) { + + IFMapNode *adj_node = static_cast(iter.operator->()); + if (cfg_listener->SkipNode(adj_node)) { + continue; + } + + if (adj_node->table() == + table->agent()->cfg()->cfg_vm_interface_table()) { + DBRequest req; + if (table->IFNodeToReq(adj_node, req) == true) { + LOG(DEBUG, "VM change sync for Port " << adj_node->name()); + table->Enqueue(&req); + } + } + } +} + const string VmInterface::GetAnalyzer() const { if (mirror_entry()) { return mirror_entry()->GetAnalyzerName(); @@ -2936,34 +3393,43 @@ void VmInterface::SendTrace(Trace event) { // VM Interface DB Table utility functions ///////////////////////////////////////////////////////////////////////////// // Add a VM-Interface -void VmInterface::Add(InterfaceTable *table, const uuid &intf_uuid, - const string &os_name, const Ip4Address &addr, - const string &mac, const string &vm_name, - const uuid &vm_project_uuid, uint16_t tx_vlan_id, - uint16_t rx_vlan_id, const std::string &parent, - const Ip6Address &ip6) { +void VmInterface::NovaAdd(InterfaceTable *table, const uuid &intf_uuid, + const string &os_name, const Ip4Address &addr, + const string &mac, const string &vm_name, + const uuid &vm_project_uuid, uint16_t tx_vlan_id, + uint16_t rx_vlan_id, const std::string &parent, + const Ip6Address &ip6) { DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE); req.key.reset(new VmInterfaceKey(AgentKey::ADD_DEL_CHANGE, intf_uuid, os_name)); - req.data.reset(new VmInterfaceAddData(addr, mac, vm_name, vm_project_uuid, - tx_vlan_id, rx_vlan_id, parent, ip6)); + + req.data.reset(new VmInterfaceNovaData(addr, ip6, mac, vm_name, nil_uuid(), + parent, tx_vlan_id, rx_vlan_id)); table->Enqueue(&req); } // Delete a VM-Interface -void VmInterface::Delete(InterfaceTable *table, const uuid &intf_uuid) { +void VmInterface::Delete(InterfaceTable *table, const uuid &intf_uuid, + VmInterface::Configurer configurer) { DBRequest req(DBRequest::DB_ENTRY_DELETE); req.key.reset(new VmInterfaceKey(AgentKey::ADD_DEL_CHANGE, intf_uuid, "")); - req.data.reset(NULL); + + if (configurer == VmInterface::CONFIG) { + req.data.reset(new VmInterfaceConfigData()); + } else if (configurer == VmInterface::EXTERNAL) { + req.data.reset(new VmInterfaceNovaData()); + } else { + assert(0); + } table->Enqueue(&req); } -bool VmInterface::CopyIp6Address(Ip6Address &addr) { +bool VmInterface::CopyIp6Address(const Ip6Address &addr) { bool ret = false; // Retain the old if new IP could not be got if (addr.is_unspecified()) { - addr = ip6_addr_; + return false; } if (ip6_addr_ != addr) { diff --git a/src/vnsw/agent/oper/vm_interface.h b/src/vnsw/agent/oper/vm_interface.h index f74cf576a7f..390d3f15d37 100644 --- a/src/vnsw/agent/oper/vm_interface.h +++ b/src/vnsw/agent/oper/vm_interface.h @@ -14,6 +14,7 @@ typedef std::vector SgUuidList; typedef std::vector SgList; struct VmInterfaceData; struct VmInterfaceConfigData; +struct VmInterfaceNovaData; struct VmInterfaceIpAddressData; struct VmInterfaceOsOperStateData; struct VmInterfaceMirrorData; @@ -27,6 +28,18 @@ class VmInterface : public Interface { public: static const uint32_t kInvalidVlanId = 0xFFFF; + enum Configurer { + EXTERNAL, + CONFIG + }; + + enum SubType { + NONE, + TOR, + NOVA, + VCPE + }; + struct ListEntry { ListEntry() : installed_(false), del_pending_(false) { } ListEntry(bool installed, bool del_pending) : @@ -116,7 +129,7 @@ class VmInterface : public Interface { StaticRoute(); StaticRoute(const StaticRoute &rhs); StaticRoute(const std::string &vrf, const IpAddress &addr, - uint32_t plen); + uint32_t plen, const IpAddress &gw); virtual ~StaticRoute(); bool operator() (const StaticRoute &lhs, const StaticRoute &rhs) const; @@ -128,6 +141,7 @@ class VmInterface : public Interface { mutable std::string vrf_; IpAddress addr_; uint32_t plen_; + IpAddress gw_; }; typedef std::set StaticRouteSet; @@ -272,7 +286,7 @@ class VmInterface : public Interface { // DBEntry vectors KeyPtr GetDBRequestKey() const; std::string ToString() const; - bool Resync(VmInterfaceData *data); + bool Resync(const InterfaceTable *table, const VmInterfaceData *data); bool OnChange(VmInterfaceData *data); // Accessor functions @@ -304,6 +318,13 @@ class VmInterface : public Interface { const Interface *parent() const { return parent_.get(); } bool ecmp() const { return ecmp_;} const OperDhcpOptions &oper_dhcp_options() const { return oper_dhcp_options_; } + uint8_t configurer() const {return configurer_;} + bool IsConfigurerSet(VmInterface::Configurer type); + void SetConfigurer(VmInterface::Configurer type); + void ResetConfigurer(VmInterface::Configurer type); + bool CanBeDeleted() const {return (configurer_ == 0);} + const Ip4Address& subnet() const { return subnet_;} + const uint8_t subnet_plen() const { return subnet_plen_;} Interface::MirrorDirection mirror_direction() const { return mirror_direction_; @@ -359,24 +380,27 @@ class VmInterface : public Interface { uint32_t GetServiceVlanLabel(const VrfEntry *vrf) const; uint32_t GetServiceVlanTag(const VrfEntry *vrf) const; const VrfEntry* GetServiceVlanVrf(uint16_t vlan_tag) const; - void Delete(); + bool Delete(const DBRequest *req); void Add(); bool OnResyncServiceVlan(VmInterfaceConfigData *data); void UpdateAllRoutes(); bool IsIpv6Active() const; + bool NeedDevice() const; + VmInterface::SubType sub_type() const {return sub_type_;} // Add a vm-interface - static void Add(InterfaceTable *table, - const boost::uuids::uuid &intf_uuid, - const std::string &os_name, const Ip4Address &addr, - const std::string &mac, const std::string &vn_name, - const boost::uuids::uuid &vm_project_uuid, - uint16_t tx_vlan_id, uint16_t rx_vlan_id, - const std::string &parent, const Ip6Address &ipv6); + static void NovaAdd(InterfaceTable *table, + const boost::uuids::uuid &intf_uuid, + const std::string &os_name, const Ip4Address &addr, + const std::string &mac, const std::string &vn_name, + const boost::uuids::uuid &vm_project_uuid, + uint16_t tx_vlan_id, uint16_t rx_vlan_id, + const std::string &parent, const Ip6Address &ipv6); // Del a vm-interface static void Delete(InterfaceTable *table, - const boost::uuids::uuid &intf_uuid); + const boost::uuids::uuid &intf_uuid, + VmInterface::Configurer configurer); // Calback from configuration static void InstanceIpSync(InterfaceTable *table, IFMapNode *node); @@ -385,6 +409,10 @@ class VmInterface : public Interface { static void FloatingIpSync(InterfaceTable *table, IFMapNode *node); static void FloatingIpVrfSync(InterfaceTable *table, IFMapNode *node); static void VnSync(InterfaceTable *table, IFMapNode *node); + static void SubnetSync(InterfaceTable *table, IFMapNode *node); + static void LogicalPortSync(InterfaceTable *table, IFMapNode *node); + static void PhysicalPortSync(InterfaceTable *table, IFMapNode *node); + static void VmSync(InterfaceTable *table, IFMapNode *node); void AllocL2MplsLabel(bool force_update, bool policy_change); void DeleteL2MplsLabel(); @@ -399,7 +427,14 @@ class VmInterface : public Interface { bool GetIpamDhcpOptions( std::vector *options, bool ipv6) const; const Peer *peer() const; + Ip4Address GetGateway() const; private: + friend struct VmInterfaceConfigData; + friend struct VmInterfaceNovaData; + friend struct VmInterfaceIpAddressData; + friend struct VmInterfaceOsOperStateData; + friend struct VmInterfaceMirrorData; + bool IsActive() const; bool IsIpv4Active() const; bool IsL3Active() const; @@ -411,6 +446,8 @@ class VmInterface : public Interface { bool ecmp, const IpAddress &gw_ip); void DeleteRoute(const std::string &vrf_name, const IpAddress &ip, uint32_t plen); + void ResolveRoute(const std::string &vrf_name, const Ip4Address &addr, + uint32_t plen, const std::string &dest_vn, bool policy); void ServiceVlanAdd(ServiceVlan &entry); void ServiceVlanDel(ServiceVlan &entry); void ServiceVlanRouteAdd(const ServiceVlan &entry); @@ -420,28 +457,30 @@ class VmInterface : public Interface { bool OnResyncSecurityGroupList(VmInterfaceConfigData *data, bool new_ipv4_active); bool OnResyncStaticRoute(VmInterfaceConfigData *data, bool new_ipv4_active); - bool ResyncMirror(VmInterfaceMirrorData *data); bool ResyncIpAddress(const VmInterfaceIpAddressData *data); bool ResyncOsOperState(const VmInterfaceOsOperStateData *data); bool ResyncConfig(VmInterfaceConfigData *data); bool CopyIpAddress(Ip4Address &addr); - bool CopyIp6Address(Ip6Address &addr); - bool CopyConfig(VmInterfaceConfigData *data, bool *sg_changed, + bool CopyIp6Address(const Ip6Address &addr); + bool CopyConfig(const InterfaceTable *table, + const VmInterfaceConfigData *data, bool *sg_changed, bool *ecmp_changed, bool *local_pref_changed); void ApplyConfig(bool old_ipv4_active,bool old_l2_active, bool old_policy, VrfEntry *old_vrf, const Ip4Address &old_addr, int old_vxlan_id, bool old_need_linklocal_ip, bool sg_changed, bool old_ipv6_active, const Ip6Address &old_v6_addr, bool ecmp_changed, - bool local_pref_changed); - + bool local_pref_changed, const Ip4Address &old_subnet, + const uint8_t old_subnet_plen); void UpdateL3(bool old_ipv4_active, VrfEntry *old_vrf, const Ip4Address &old_addr, int old_vxlan_id, bool force_update, bool policy_change, bool old_ipv6_active, - const Ip6Address &old_v6_addr); + const Ip6Address &old_v6_addr, const Ip4Address &subnet, + const uint8_t old_subnet_plen); void DeleteL3(bool old_ipv4_active, VrfEntry *old_vrf, const Ip4Address &old_addr, bool old_need_linklocal_ip, - bool old_ipv6_active, const Ip6Address &old_v6_addr); + bool old_ipv6_active, const Ip6Address &old_v6_addr, + const Ip4Address &old_subnet, const uint8_t old_subnet_plen); void UpdateL2(bool old_l2_active, VrfEntry *old_vrf, int old_vxlan_id, bool force_update, bool policy_change); void DeleteL2(bool old_l2_active, VrfEntry *old_vrf); @@ -474,6 +513,11 @@ class VmInterface : public Interface { const Ip6Address &old_addr); void DeleteIpv6InterfaceRoute(VrfEntry *old_vrf, const Ip6Address &old_addr); + void UpdateResolveRoute(bool old_ipv4_active, bool force_update, + bool policy_change, VrfEntry * old_vrf, + const Ip4Address &old_addr, uint8_t old_plen); + void DeleteResolveRoute(VrfEntry *old_vrf, + const Ip4Address &old_addr, const uint8_t old_plen); void DeleteInterfaceNH(); void UpdateMetadataRoute(bool old_ipv4_active, VrfEntry *old_vrf); void DeleteMetadataRoute(bool old_ipv4_active, VrfEntry *old_vrf, @@ -548,6 +592,11 @@ class VmInterface : public Interface { AclDBEntryRef vrf_assign_acl_; Ip4Address vm_ip_gw_addr_; Ip6Address vm_ip6_gw_addr_; + VmInterface::SubType sub_type_; + uint8_t configurer_; + IFMapNode *ifmap_node_; + Ip4Address subnet_; + uint8_t subnet_plen_; DISALLOW_COPY_AND_ASSIGN(VmInterface); }; @@ -567,25 +616,23 @@ struct VmInterfaceKey : public InterfaceKey { ///////////////////////////////////////////////////////////////////////////// // The base class for different type of InterfaceData used for VmInterfaces. +// // Request for VM-Interface data are of 3 types // - ADD_DEL_CHANGE -// VM Interface are not added from IFMap config messages. In case of -// Openstack, VM-Interfaces are added by a message from Nova. -// Data of type ADD_DEL_CHANGE is used when interface is created -// - CONFIG -// Data dervied from the IFMap configuration +// Message for ADD/DEL/CHANGE of an interface // - MIRROR // Data for mirror enable/disable // - IP_ADDR // In one of the modes, the IP address for an interface is not got from IFMap // or Nova. Agent will relay DHCP Request in such cases to IP Fabric network. // The IP address learnt with DHCP in this case is confgured with this type -// +// - OS_OPER_STATE +// Update to oper state of the interface ///////////////////////////////////////////////////////////////////////////// struct VmInterfaceData : public InterfaceData { enum Type { - ADD_DEL_CHANGE, CONFIG, + NOVA, MIRROR, IP_ADDR, OS_OPER_STATE @@ -595,45 +642,39 @@ struct VmInterfaceData : public InterfaceData { VmPortInit(); } virtual ~VmInterfaceData() { } - - Type type_; -}; - -// Structure used when type=ADD_DEL_CHANGE. Used for creating of Vm-Interface -struct VmInterfaceAddData : public VmInterfaceData { - VmInterfaceAddData(const Ip4Address &ip_addr, - const std::string &vm_mac, - const std::string &vm_name, - const boost::uuids::uuid &vm_project_uuid, - const uint16_t tx_vlan_id, const uint16_t rx_vlan_id, - const std::string &parent, const Ip6Address &ip6_addr) : - VmInterfaceData(ADD_DEL_CHANGE), ip_addr_(ip_addr), ip6_addr_(ip6_addr), - vm_mac_(vm_mac), vm_name_(vm_name), vm_project_uuid_(vm_project_uuid), - tx_vlan_id_(tx_vlan_id), rx_vlan_id_(rx_vlan_id), parent_(parent) { + virtual VmInterface *OnAdd(const InterfaceTable *table, + const VmInterfaceKey *key) const { + return NULL; } + virtual bool OnDelete(const InterfaceTable *table, + VmInterface *entry) const { + return true; + } + virtual bool OnResync(const InterfaceTable *table, VmInterface *vmi, + bool *sg_changed, bool *ecmp_changed, + bool *local_pref_changed) const = 0; - virtual ~VmInterfaceAddData() { } - - Ip4Address ip_addr_; - Ip6Address ip6_addr_; - std::string vm_mac_; - std::string vm_name_; - boost::uuids::uuid vm_project_uuid_; - uint16_t tx_vlan_id_; - uint16_t rx_vlan_id_; - std::string parent_; + Type type_; }; // Structure used when type=IP_ADDR. Used to update IP-Address of VM-Interface +// The IP Address is picked up from the DHCP Snoop table struct VmInterfaceIpAddressData : public VmInterfaceData { VmInterfaceIpAddressData() : VmInterfaceData(IP_ADDR) { } virtual ~VmInterfaceIpAddressData() { } + virtual bool OnResync(const InterfaceTable *table, VmInterface *vmi, + bool *sg_changed, bool *ecmp_changed, + bool *local_pref_changed) const; }; // Structure used when type=OS_OPER_STATE Used to update interface os oper-state +// The current oper-state is got by querying the device struct VmInterfaceOsOperStateData : public VmInterfaceData { VmInterfaceOsOperStateData() : VmInterfaceData(OS_OPER_STATE) { } virtual ~VmInterfaceOsOperStateData() { } + virtual bool OnResync(const InterfaceTable *table, VmInterface *vmi, + bool *sg_changed, bool *ecmp_changed, + bool *local_pref_changed) const; }; // Structure used when type=MIRROR. Used to update IP-Address of VM-Interface @@ -642,6 +683,10 @@ struct VmInterfaceMirrorData : public VmInterfaceData { VmInterfaceData(MIRROR), mirror_enable_(mirror_enable), analyzer_name_(analyzer_name) { } + virtual ~VmInterfaceMirrorData() { } + virtual bool OnResync(const InterfaceTable *table, VmInterface *vmi, + bool *sg_changed, bool *ecmp_changed, + bool *local_pref_changed) const; bool mirror_enable_; std::string analyzer_name_; @@ -658,23 +703,20 @@ struct VmInterfaceConfigData : public VmInterfaceData { local_preference_(VmInterface::INVALID), oper_dhcp_options_(), mirror_direction_(Interface::UNKNOWN), sg_list_(), floating_ip_list_(), service_vlan_list_(), static_route_list_(), - allowed_address_pair_list_() { - } - - VmInterfaceConfigData(const Ip4Address &addr, const std::string &mac, - const std::string &vm_name) : - VmInterfaceData(CONFIG), addr_(addr), ip6_addr_(), vm_mac_(mac), - cfg_name_(""), vm_uuid_(), vm_name_(vm_name), vn_uuid_(), vrf_name_(""), - fabric_port_(true), need_linklocal_ip_(false), - layer2_forwarding_(true), layer3_forwarding_(true), - mirror_enable_(false), ecmp_(false), dhcp_enable_(true), - analyzer_name_(""), local_preference_(VmInterface::INVALID), oper_dhcp_options_(), - mirror_direction_(Interface::UNKNOWN), sg_list_(), - floating_ip_list_(), service_vlan_list_(), static_route_list_(), - allowed_address_pair_list_() { + allowed_address_pair_list_(), sub_type_(VmInterface::NONE), + parent_(""), ifmap_node_(NULL), subnet_(0), subnet_plen_(0), + rx_vlan_id_(VmInterface::kInvalidVlanId), + tx_vlan_id_(VmInterface::kInvalidVlanId) { } virtual ~VmInterfaceConfigData() { } + virtual VmInterface *OnAdd(const InterfaceTable *table, + const VmInterfaceKey *key) const; + virtual bool OnDelete(const InterfaceTable *table, + VmInterface *entry) const; + virtual bool OnResync(const InterfaceTable *table, VmInterface *vmi, + bool *sg_changed, bool *ecmp_changed, + bool *local_pref_changed) const; Ip4Address addr_; Ip6Address ip6_addr_; @@ -706,6 +748,43 @@ struct VmInterfaceConfigData : public VmInterfaceData { VmInterface::StaticRouteList static_route_list_; VmInterface::VrfAssignRuleList vrf_assign_rule_list_; VmInterface::AllowedAddressPairList allowed_address_pair_list_; + VmInterface::SubType sub_type_; + std::string parent_; + IFMapNode *ifmap_node_; + Ip4Address subnet_; + uint8_t subnet_plen_; + uint16_t rx_vlan_id_; + uint16_t tx_vlan_id_; +}; + +// Definition for structures when request queued from Nova +struct VmInterfaceNovaData : public VmInterfaceData { + VmInterfaceNovaData(); + VmInterfaceNovaData(const Ip4Address &ipv4_addr, + const Ip6Address &ipv6_addr, + const std::string &mac_addr, + const std::string vm_name, + boost::uuids::uuid vm_uuid, + const std::string &parent, + uint16_t tx_vlan_id, + uint16_t rx_vlan_id); + virtual ~VmInterfaceNovaData(); + virtual VmInterface *OnAdd(const InterfaceTable *table, + const VmInterfaceKey *key) const; + virtual bool OnDelete(const InterfaceTable *table, + VmInterface *entry) const; + virtual bool OnResync(const InterfaceTable *table, VmInterface *vmi, + bool *sg_changed, bool *ecmp_changed, + bool *local_pref_changed) const; + + Ip4Address ipv4_addr_; + Ip6Address ipv6_addr_; + std::string mac_addr_; + std::string vm_name_; + boost::uuids::uuid vm_uuid_; + std::string parent_; + uint16_t tx_vlan_id_; + uint16_t rx_vlan_id_; }; #endif // vnsw_agent_vm_interface_hpp diff --git a/src/vnsw/agent/oper/vn.cc b/src/vnsw/agent/oper/vn.cc index af5413ae0b9..f7994c8c3d8 100644 --- a/src/vnsw/agent/oper/vn.cc +++ b/src/vnsw/agent/oper/vn.cc @@ -328,9 +328,18 @@ bool VnTable::ChangeHandler(DBEntry *entry, const DBRequest *req) { VrfEntry *vrf = static_cast (Agent::GetInstance()->vrf_table()->FindActiveEntry(&vrf_key)); if (vrf != old_vrf) { - if (!vrf) + if (!vrf) { DeleteAllIpamRoutes(vn); + if (vn->table_label()) { + MplsLabel::Delete(vn->table_label()); + vn->set_table_label(0); + } + } vn->vrf_ = vrf; + if (vrf) { + vn->set_table_label(Agent::GetInstance()->mpls_table()->AllocLabel()); + MplsLabel::CreateTableLabel(vn->table_label(), data->vrf_name_, false); + } ret = true; } @@ -370,6 +379,10 @@ bool VnTable::ChangeHandler(DBEntry *entry, const DBRequest *req) { bool VnTable::Delete(DBEntry *entry, const DBRequest *req) { VnEntry *vn = static_cast(entry); DeleteAllIpamRoutes(vn); + if (vn->table_label()) { + MplsLabel::Delete(vn->table_label()); + vn->set_table_label(0); + } vn->SendObjectLog(AgentLogEvent::DELETE); return true; } @@ -534,6 +547,7 @@ bool VnTable::IFNodeToReq(IFMapNode *node, DBRequest &req) { VnIpam(subnets.ipam_subnets[i].subnet.ip_prefix, subnets.ipam_subnets[i].subnet.ip_prefix_len, subnets.ipam_subnets[i].default_gateway, + subnets.ipam_subnets[i].dns_server_address, subnets.ipam_subnets[i].enable_dhcp, ipam_name, subnets.ipam_subnets[i].dhcp_option_list.dhcp_option, subnets.ipam_subnets[i].host_routes.route)); @@ -644,15 +658,15 @@ void VnTable::IpamVnSync(IFMapNode *node) { return; } -void VnTable::UpdateSubnetGateway(const VnIpam &old_ipam, - const VnIpam &new_ipam, - VnEntry *vn) { +void VnTable::UpdateHostRoute(const IpAddress &old_address, + const IpAddress &new_address, + VnEntry *vn) { VrfEntry *vrf = vn->GetVrf(); if (vrf && (vrf->GetName() != Agent::GetInstance()-> linklocal_vrf_name())) { - AddHostRouteForGw(vn, new_ipam); - DelHostRouteForGw(vn, old_ipam); + AddHostRoute(vn, new_address); + DelHostRoute(vn, old_address); } } @@ -679,24 +693,36 @@ bool VnTable::IpamChangeNotify(std::vector &old_ipam, } else { //Evaluate non key members of IPAM for changes. // no change in entry - bool gateway_changed = ((*it_old).default_gw != + bool gateway_changed = ((*it_old).default_gw != (*it_new).default_gw); + bool service_address_changed = ((*it_old).dns_server != (*it_new).dns_server); if ((*it_old).installed) { (*it_new).installed = true; // VNIPAM comparator does not check for gateway. // If gateway is changed then take appropriate actions. + IpAddress unspecified; if (gateway_changed) { - UpdateSubnetGateway((*it_old), (*it_new), vn); + if (IsGwHostRouteRequired()) { + UpdateHostRoute((*it_old).default_gw, + (*it_new).default_gw, vn); + } + } + if (service_address_changed) { + UpdateHostRoute((*it_old).dns_server, + (*it_new).dns_server, vn); } } else { AddIPAMRoutes(vn, *it_new); (*it_old).installed = (*it_new).installed; } - if (gateway_changed) { + if (gateway_changed) { (*it_old).default_gw = (*it_new).default_gw; } + if (service_address_changed) { + (*it_old).dns_server = (*it_new).dns_server; + } // update DHCP options (*it_old).oper_dhcp_options = (*it_new).oper_dhcp_options; @@ -743,7 +769,9 @@ void VnTable::AddIPAMRoutes(VnEntry *vn, VnIpam &ipam) { if (vrf->GetName() == Agent::GetInstance()->linklocal_vrf_name()) { return; } - AddHostRouteForGw(vn, ipam); + if (IsGwHostRouteRequired()) + AddHostRoute(vn, ipam.default_gw); + AddHostRoute(vn, ipam.dns_server); AddSubnetRoute(vn, ipam); ipam.installed = true; } @@ -752,39 +780,45 @@ void VnTable::AddIPAMRoutes(VnEntry *vn, VnIpam &ipam) { void VnTable::DelIPAMRoutes(VnEntry *vn, VnIpam &ipam) { VrfEntry *vrf = vn->GetVrf(); if (vrf && ipam.installed) { - DelHostRouteForGw(vn, ipam); + if (IsGwHostRouteRequired()) + DelHostRoute(vn, ipam.default_gw); + DelHostRoute(vn, ipam.dns_server); DelSubnetRoute(vn, ipam); ipam.installed = false; } } +bool VnTable::IsGwHostRouteRequired() { + return (!agent()->tsn_enabled()); +} + // Add receive route for default gw -void VnTable::AddHostRouteForGw(VnEntry *vn, const VnIpam &ipam) { +void VnTable::AddHostRoute(VnEntry *vn, const IpAddress &address) { VrfEntry *vrf = vn->GetVrf(); - if (ipam.IsV4()) { + if (address.is_v4()) { static_cast(vrf-> GetInet4UnicastRouteTable())->AddHostRoute(vrf->GetName(), - ipam.default_gw.to_v4(), 32, vn->GetName()); - } else if (ipam.IsV6()) { + address.to_v4(), 32, vn->GetName()); + } else if (address.is_v6()) { static_cast(vrf-> GetInet6UnicastRouteTable())->AddHostRoute(vrf->GetName(), - ipam.default_gw.to_v6(), 128, vn->GetName()); + address.to_v6(), 128, vn->GetName()); } } // Del receive route for default gw -void VnTable::DelHostRouteForGw(VnEntry *vn, const VnIpam &ipam) { +void VnTable::DelHostRoute(VnEntry *vn, const IpAddress &address) { VrfEntry *vrf = vn->GetVrf(); - if (ipam.IsV4()) { + if (address.is_v4()) { static_cast (vrf->GetInet4UnicastRouteTable())->DeleteReq (Agent::GetInstance()->local_peer(), vrf->GetName(), - ipam.default_gw.to_v4(), 32, NULL); - } else if (ipam.IsV6()) { + address.to_v4(), 32, NULL); + } else if (address.is_v6()) { static_cast (vrf->GetInet6UnicastRouteTable())->DeleteReq (Agent::GetInstance()->local_peer(), vrf->GetName(), - ipam.default_gw.to_v6(), 128, NULL); + address.to_v6(), 128, NULL); } } @@ -858,6 +892,7 @@ bool VnEntry::DBEntrySandesh(Sandesh *sresp, std::string &name) const { entry.set_gateway(vn_ipam[i].default_gw.to_string()); entry.set_ipam_name(vn_ipam[i].ipam_name); entry.set_dhcp_enable(vn_ipam[i].dhcp_enable ? "true" : "false"); + entry.set_dns_server(vn_ipam[i].dns_server.to_string()); vn_subnet_sandesh_list.push_back(entry); } data.set_ipam_data(vn_subnet_sandesh_list); @@ -879,6 +914,7 @@ bool VnEntry::DBEntrySandesh(Sandesh *sresp, std::string &name) const { data.set_ipv4_forwarding(layer3_forwarding()); data.set_layer2_forwarding(layer2_forwarding()); data.set_admin_state(admin_state()); + data.set_table_label(table_label()); std::vector &list = const_cast&>(resp->get_vn_list()); @@ -945,6 +981,8 @@ void VnEntry::SendObjectLog(AgentLogEvent::type event) const { sandesh_ipam.set_prefix_len(ipam.plen); sandesh_ipam.set_gateway_ip(ipam.default_gw.to_string()); sandesh_ipam.set_ipam_name(ipam.ipam_name); + sandesh_ipam.set_dhcp_enable(ipam.dhcp_enable ? "true" : "false"); + sandesh_ipam.set_dns_server(ipam.dns_server.to_string()); ipam_list.push_back(sandesh_ipam); ++it; } diff --git a/src/vnsw/agent/oper/vn.h b/src/vnsw/agent/oper/vn.h index c9d8b68bfe4..7e0985ad338 100644 --- a/src/vnsw/agent/oper/vn.h +++ b/src/vnsw/agent/oper/vn.h @@ -28,19 +28,22 @@ struct VnIpam { IpAddress ip_prefix; uint32_t plen; IpAddress default_gw; + // In case of TSN, we could have different addresses for default_gw & dns + IpAddress dns_server; bool installed; // is the route to send pkts to host installed bool dhcp_enable; std::string ipam_name; OperDhcpOptions oper_dhcp_options; VnIpam(const std::string& ip, uint32_t len, const std::string& gw, - bool dhcp, std::string &name, + const std::string& dns, bool dhcp, std::string &name, const std::vector &dhcp_options, const std::vector &host_routes) : plen(len), installed(false), dhcp_enable(dhcp), ipam_name(name) { boost::system::error_code ec; ip_prefix = IpAddress::from_string(ip, ec); default_gw = IpAddress::from_string(gw, ec); + dns_server = IpAddress::from_string(dns, ec); oper_dhcp_options.set_options(dhcp_options); oper_dhcp_options.set_host_routes(host_routes); } @@ -141,7 +144,7 @@ struct VnData : public AgentData { class VnEntry : AgentRefCount, public AgentDBEntry { public: VnEntry(uuid id) : uuid_(id), vxlan_id_(0), vnid_(0), layer2_forwarding_(true), - layer3_forwarding_(true), admin_state_(true) { } + layer3_forwarding_(true), admin_state_(true), table_label_(0) { } virtual ~VnEntry() { }; virtual bool IsLess(const DBEntry &rhs) const; @@ -184,6 +187,10 @@ class VnEntry : AgentRefCount, public AgentDBEntry { bool layer2_forwarding() const {return layer2_forwarding_;}; bool layer3_forwarding() const {return layer3_forwarding_;}; bool admin_state() const {return admin_state_;} + uint32_t table_label() const { return table_label_;} + void set_table_label(uint32_t label) { + table_label_ = label; + } AgentDBTable *DBToTable() const; uint32_t GetRefCount() const { @@ -211,6 +218,7 @@ class VnEntry : AgentRefCount, public AgentDBEntry { bool layer3_forwarding_; bool admin_state_; VxLanIdRef vxlan_id_ref_; + uint32_t table_label_; DISALLOW_COPY_AND_ASSIGN(VnEntry); }; @@ -250,15 +258,16 @@ class VnTable : public AgentDBTable { static VnTable *vn_table_; bool IpamChangeNotify(std::vector &old_ipam, std::vector &new_ipam, VnEntry *vn); - void UpdateSubnetGateway(const VnIpam &old_ipam, const VnIpam &new_ipam, - VnEntry *vn); + void UpdateHostRoute(const IpAddress &old_address, + const IpAddress &new_address, VnEntry *vn); void AddIPAMRoutes(VnEntry *vn, VnIpam &ipam); void DelIPAMRoutes(VnEntry *vn, VnIpam &ipam); void DeleteAllIpamRoutes(VnEntry *vn); void AddSubnetRoute(VnEntry *vn, VnIpam &ipam); void DelSubnetRoute(VnEntry *vn, VnIpam &ipam); - void AddHostRouteForGw(VnEntry *vn, const VnIpam &ipam); - void DelHostRouteForGw(VnEntry *vn, const VnIpam &ipam); + bool IsGwHostRouteRequired(); + void AddHostRoute(VnEntry *vn, const IpAddress &address); + void DelHostRoute(VnEntry *vn, const IpAddress &address); bool ChangeHandler(DBEntry *entry, const DBRequest *req); bool IsGatewayL2(const string &gateway) const; IFMapNode *FindTarget(IFMapAgentTable *table, IFMapNode *node, diff --git a/src/vnsw/agent/oper/vrf.cc b/src/vnsw/agent/oper/vrf.cc index d457d89802b..58476c4cb3a 100644 --- a/src/vnsw/agent/oper/vrf.cc +++ b/src/vnsw/agent/oper/vrf.cc @@ -303,6 +303,7 @@ bool VrfTable::OnChange(DBEntry *entry, const DBRequest *req) { VnEntry *vn = agent()->vn_table()->Find(data->vn_uuid_); if (vn != vrf->vn_.get()) { vrf->vn_.reset(vn); + return true; } return false; } diff --git a/src/vnsw/agent/physical_devices/SConscript b/src/vnsw/agent/physical_devices/SConscript index 16f35b73a8d..d699b73fb94 100644 --- a/src/vnsw/agent/physical_devices/SConscript +++ b/src/vnsw/agent/physical_devices/SConscript @@ -10,4 +10,5 @@ env = AgentEnv.Clone() env.SConscript('tables/SConscript', exports='AgentEnv', duplicate=0) env.SConscript('ovs_tor_agent/SConscript', exports='AgentEnv', duplicate=0) +env.SConscript('tsn/SConscript', exports='AgentEnv', duplicate=0) env.SConscript('test/SConscript', exports='AgentEnv', duplicate=0) diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/SConscript b/src/vnsw/agent/physical_devices/ovs_tor_agent/SConscript index 21ac69d6a80..e934174ccd8 100644 --- a/src/vnsw/agent/physical_devices/ovs_tor_agent/SConscript +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/SConscript @@ -13,9 +13,20 @@ import subprocess Import('AgentEnv') env = AgentEnv.Clone() -env.Append(LIBPATH = [ '../tables' ]) -env.Prepend(LIBS = [ 'vnswinit' ]) -env.Append(LIBS = [ 'physical_devices' ]) +env.Append(LIBPATH = [ + '../tables', + 'ovsdb_client' + ]) +env.Prepend(LIBS = [ + 'ovsdbclient', + 'openvswitch', + 'vnswinit' + ]) +env.Append(LIBS = [ + 'physical_devices' + ]) + +env.Append(LIBS = ['ssl', 'crypto']) env.GenerateBuildInfoCode( target='buildinfo.cc', @@ -29,13 +40,13 @@ env.AppendUnique(CCFLAGS='-Wno-return-type') tor_agent = env.Program(target = 'tor_agent', source = [ 'buildinfo.cc', - 'ovs_peer.cc', 'tor_agent_param.cc', 'tor_agent_init.cc', 'main.cc', ]) env.Alias('agent:tor_agent', tor_agent) +env.SConscript('ovsdb_client/SConscript', exports='AgentEnv', duplicate=0) # Local Variables: # mode: python diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/main.cc b/src/vnsw/agent/physical_devices/ovs_tor_agent/main.cc index 999826da857..f1751d9c431 100644 --- a/src/vnsw/agent/physical_devices/ovs_tor_agent/main.cc +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/main.cc @@ -62,6 +62,7 @@ int main(int argc, char *argv[]) { MiscUtils::LogVersionInfo(build_info, Category::VROUTER); init.set_agent_param(¶ms); + agent->set_agent_init(&init); // Read agent parameters from config file and arguments init.ProcessOptions(init_file, argv[0]); diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovs_peer.cc b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovs_peer.cc deleted file mode 100644 index 9f0b94c0cec..00000000000 --- a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovs_peer.cc +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. - */ -#include - -OvsPeer::OvsPeer(const IpAddress &peer_ip, uint64_t gen_id) : - Peer(Peer::OVS_PEER, "OVS-" + peer_ip.to_string()), peer_ip_(peer_ip), - gen_id_(gen_id) { -} - -OvsPeer::~OvsPeer() { -} - -bool OvsPeer::Compare(const Peer *rhs) const { - const OvsPeer *rhs_peer = static_cast(rhs); - if (gen_id_ != rhs_peer->gen_id_) - return gen_id_ < rhs_peer->gen_id_; - - return peer_ip_ < rhs_peer->peer_ip_; -} - -OvsPeerManager::OvsPeerManager() : gen_id_(0) { -} - -OvsPeerManager::~OvsPeerManager() { - assert(table_.size() == 0); -} - -OvsPeer *OvsPeerManager::Allocate(const IpAddress &peer_ip) { - OvsPeer *peer = new OvsPeer(peer_ip, gen_id_++); - table_.insert(peer); -} - -void OvsPeerManager::Free(OvsPeer *peer) { - table_.erase(peer); - delete peer; -} diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/SConscript b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/SConscript new file mode 100644 index 00000000000..068f3aba6ec --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/SConscript @@ -0,0 +1,45 @@ +# +# Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. +# + +# -*- mode: python; -*- + +Import('AgentEnv') + +env = AgentEnv.Clone() +env.CppEnableExceptions() + +env.Append(CPPPATH = './') +env.Append(CPPPATH = '#/build/include/openvswitch/include') +env.Append(CPPPATH = '#/build/include/openvswitch/lib') +env.Append(LIBPATH = '#/build/lib') +env.Append(LIBS = 'openvswitch') + +SandeshGenFiles = env.SandeshGenCpp('ovsdb.sandesh') +SandeshGenSrcs = env.ExtractCpp(SandeshGenFiles) +sandesh_objs = AgentEnv.BuildExceptionCppObj(env, SandeshGenSrcs) + +libovsdbclient = env.Library('ovsdbclient', + sandesh_objs + + [ + 'logical_switch_ovsdb.cc', + 'ovsdb_client.cc', + 'ovsdb_client_idl.cc', + 'ovsdb_client_session.cc', + 'ovsdb_client_tcp.cc', + 'ovsdb_entry.cc', + 'ovsdb_object.cc', + 'ovsdb_route_data.cc', + 'ovsdb_route_peer.cc', + 'ovsdb_wrapper.c', + 'physical_locator_ovsdb.cc', + 'physical_port_ovsdb.cc', + 'physical_switch_ovsdb.cc', + 'unicast_mac_local_ovsdb.cc', + 'unicast_mac_remote_ovsdb.cc', + 'vlan_port_binding_ovsdb.cc', + 'vm_interface_ksync.cc' + ]) +env.Requires(libovsdbclient, '#/build/include/openvswitch/include') + +env.SConscript('test/SConscript', exports='AgentEnv', duplicate=0) diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/logical_switch_ovsdb.cc b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/logical_switch_ovsdb.cc new file mode 100644 index 00000000000..a7d730c5aeb --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/logical_switch_ovsdb.cc @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +extern "C" { +#include +}; +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace AGENT; +using OVSDB::LogicalSwitchEntry; +using OVSDB::LogicalSwitchTable; +using OVSDB::OvsdbDBEntry; +using OVSDB::OvsdbDBObject; +using OVSDB::OvsdbClient; +using OVSDB::OvsdbClientSession; + +LogicalSwitchEntry::LogicalSwitchEntry(OvsdbDBObject *table, + const AGENT::PhysicalDeviceVnEntry *entry) : OvsdbDBEntry(table), + name_(UuidToString(entry->vn()->GetUuid())), mcast_local_row_(NULL), + mcast_remote_row_(NULL), old_mcast_remote_row_(NULL) { + vxlan_id_ = entry->vn()->GetVxLanId(); + device_name_ = entry->device()->name(); +} + +LogicalSwitchEntry::LogicalSwitchEntry(OvsdbDBObject *table, + const LogicalSwitchEntry *entry) : OvsdbDBEntry(table), + mcast_local_row_(NULL), mcast_remote_row_(NULL), + old_mcast_remote_row_(NULL) { + name_ = entry->name_; + vxlan_id_ = entry->vxlan_id_;; + device_name_ = entry->device_name_; +} + +LogicalSwitchEntry::LogicalSwitchEntry(OvsdbDBObject *table, + struct ovsdb_idl_row *entry) : OvsdbDBEntry(table, entry), + name_(ovsdb_wrapper_logical_switch_name(entry)), device_name_(""), + vxlan_id_(ovsdb_wrapper_logical_switch_tunnel_key(entry)), + mcast_local_row_(NULL), mcast_remote_row_(NULL), + old_mcast_remote_row_(NULL) { +} + +Ip4Address &LogicalSwitchEntry::physical_switch_tunnel_ip() { + PhysicalSwitchEntry *p_switch = + static_cast(physical_switch_.get()); + return p_switch->tunnel_ip(); +} + +void LogicalSwitchEntry::AddMsg(struct ovsdb_idl_txn *txn) { + PhysicalSwitchTable *p_table = table_->client_idl()->physical_switch_table(); + PhysicalSwitchEntry key(p_table, device_name_.c_str()); + physical_switch_ = p_table->GetReference(&key); + struct ovsdb_idl_row *row = + ovsdb_wrapper_add_logical_switch(txn, ovs_entry_, name_.c_str(), + vxlan_id_); + /* Add remote multicast entry if not already present */ + if (mcast_remote_row_ == NULL) { + std::string dest_ip = table_->client_idl()->tsn_ip().to_string(); + PhysicalLocatorTable *pl_table = + table_->client_idl()->physical_locator_table(); + PhysicalLocatorEntry pl_key(pl_table, dest_ip); + /* + * we don't take reference to physical locator, just use if locator + * is existing or we will create a new one. + */ + PhysicalLocatorEntry *pl_entry = + static_cast(pl_table->Find(&pl_key)); + struct ovsdb_idl_row *pl_row = NULL; + if (pl_entry) + pl_row = pl_entry->ovs_entry(); + ovsdb_wrapper_add_mcast_mac_remote(txn, NULL, "unknown-dst", row, + pl_row, dest_ip.c_str()); + } + if (old_mcast_remote_row_ != NULL) { + ovsdb_wrapper_delete_mcast_mac_remote(old_mcast_remote_row_); + } + SendTrace(LogicalSwitchEntry::ADD_REQ); +} + +void LogicalSwitchEntry::ChangeMsg(struct ovsdb_idl_txn *txn) { + AddMsg(txn); +} + +void LogicalSwitchEntry::DeleteMsg(struct ovsdb_idl_txn *txn) { + physical_switch_ = NULL; + if (mcast_local_row_ != NULL) { + ovsdb_wrapper_delete_mcast_mac_local(mcast_local_row_); + } + if (mcast_remote_row_ != NULL) { + ovsdb_wrapper_delete_mcast_mac_remote(mcast_remote_row_); + } + if (old_mcast_remote_row_ != NULL) { + ovsdb_wrapper_delete_mcast_mac_remote(old_mcast_remote_row_); + } + if (ovs_entry_ != NULL) { + ovsdb_wrapper_delete_logical_switch(ovs_entry_); + } + SendTrace(LogicalSwitchEntry::DEL_REQ); +} + +void LogicalSwitchEntry::OvsdbChange() { + if (!IsResolved()) + table_->NotifyEvent(this, KSyncEntry::ADD_CHANGE_REQ); +} + +const std::string &LogicalSwitchEntry::name() const { + return name_; +} + +const std::string &LogicalSwitchEntry::device_name() const { + return device_name_; +} + +int64_t LogicalSwitchEntry::vxlan_id() const { + return vxlan_id_; +} + +bool LogicalSwitchEntry::Sync(DBEntry *db_entry) { + PhysicalDeviceVnEntry *entry = + static_cast(db_entry); + bool change = false; + if (vxlan_id_ != entry->vn()->GetVxLanId()) { + vxlan_id_ = entry->vn()->GetVxLanId(); + change = true; + } + if (device_name_ != entry->device()->name()) { + device_name_ = entry->device()->name(); + change = true; + } + return change; +} + +bool LogicalSwitchEntry::IsLess(const KSyncEntry &entry) const { + const LogicalSwitchEntry &ps_entry = + static_cast(entry); + return (name_.compare(ps_entry.name_) < 0); +} + +KSyncEntry *LogicalSwitchEntry::UnresolvedReference() { + PhysicalSwitchTable *p_table = table_->client_idl()->physical_switch_table(); + PhysicalSwitchEntry key(p_table, device_name_.c_str()); + PhysicalSwitchEntry *p_switch = + static_cast(p_table->GetReference(&key)); + if (!p_switch->IsResolved()) { + return p_switch; + } + return NULL; +} + +void LogicalSwitchEntry::SendTrace(Trace event) const { + SandeshLogicalSwitchInfo info; + switch (event) { + case ADD_REQ: + info.set_op("Add Requested"); + break; + case DEL_REQ: + info.set_op("Delete Requested"); + break; + case ADD_ACK: + info.set_op("Add Received"); + break; + case DEL_ACK: + info.set_op("Delete Received"); + break; + default: + info.set_op("unknown"); + } + info.set_name(name_); + info.set_device_name(device_name_); + info.set_vxlan(vxlan_id_); + OVSDB_TRACE(LogicalSwitch, info); +} + +LogicalSwitchTable::LogicalSwitchTable(OvsdbClientIdl *idl, DBTable *table) : + OvsdbDBObject(idl, table) { + idl->Register(OvsdbClientIdl::OVSDB_LOGICAL_SWITCH, + boost::bind(&LogicalSwitchTable::OvsdbNotify, this, _1, _2)); + idl->Register(OvsdbClientIdl::OVSDB_MCAST_MAC_LOCAL, + boost::bind(&LogicalSwitchTable::OvsdbMcastLocalMacNotify, + this, _1, _2)); + idl->Register(OvsdbClientIdl::OVSDB_MCAST_MAC_REMOTE, + boost::bind(&LogicalSwitchTable::OvsdbMcastRemoteMacNotify, + this, _1, _2)); +} + +LogicalSwitchTable::~LogicalSwitchTable() { + client_idl_->UnRegister(OvsdbClientIdl::OVSDB_LOGICAL_SWITCH); + client_idl_->UnRegister(OvsdbClientIdl::OVSDB_MCAST_MAC_LOCAL); + client_idl_->UnRegister(OvsdbClientIdl::OVSDB_MCAST_MAC_REMOTE); +} + +void LogicalSwitchTable::OvsdbNotify(OvsdbClientIdl::Op op, + struct ovsdb_idl_row *row) { + LogicalSwitchEntry key(this, row); + if (op == OvsdbClientIdl::OVSDB_DEL) { + NotifyDeleteOvsdb((OvsdbDBEntry*)&key); + key.SendTrace(LogicalSwitchEntry::DEL_ACK); + } else if (op == OvsdbClientIdl::OVSDB_ADD) { + NotifyAddOvsdb((OvsdbDBEntry*)&key, row); + key.SendTrace(LogicalSwitchEntry::ADD_ACK); + } else { + assert(0); + } +} + +void LogicalSwitchTable::OvsdbMcastLocalMacNotify(OvsdbClientIdl::Op op, + struct ovsdb_idl_row *row) { + const char *mac = ovsdb_wrapper_mcast_mac_local_mac(row); + const char *ls = ovsdb_wrapper_mcast_mac_local_logical_switch(row); + LogicalSwitchEntry *entry = NULL; + if (ls) { + LogicalSwitchEntry key(this, ls); + entry = static_cast(Find(&key)); + } + if (op == OvsdbClientIdl::OVSDB_DEL) { + OVSDB_TRACE(Trace, "Delete : Local Mcast MAC " + std::string(mac) + + ", logical switch " + (ls ? std::string(ls) : "")); + if (entry) { + entry->mcast_local_row_ = NULL; + } + } else if (op == OvsdbClientIdl::OVSDB_ADD) { + OVSDB_TRACE(Trace, "Add : Local Mcast MAC " + std::string(mac) + + ", logical switch " + (ls ? std::string(ls) : "")); + if (entry) { + entry->mcast_local_row_ = row; + } + } else { + assert(0); + } +} + +void LogicalSwitchTable::OvsdbMcastRemoteMacNotify(OvsdbClientIdl::Op op, + struct ovsdb_idl_row *row) { + const char *mac = ovsdb_wrapper_mcast_mac_remote_mac(row); + const char *ls = ovsdb_wrapper_mcast_mac_remote_logical_switch(row); + LogicalSwitchEntry *entry = NULL; + if (ls) { + LogicalSwitchEntry key(this, ls); + entry = static_cast(Find(&key)); + } + if (op == OvsdbClientIdl::OVSDB_DEL) { + OVSDB_TRACE(Trace, "Delete : Remote Mcast MAC " + std::string(mac) + + ", logical switch " + (ls ? std::string(ls) : "")); + if (entry) { + if (entry->old_mcast_remote_row_ == row) + entry->old_mcast_remote_row_ = NULL; + if (entry->mcast_remote_row_ == row) + entry->mcast_remote_row_ = NULL; + } + } else if (op == OvsdbClientIdl::OVSDB_ADD) { + OVSDB_TRACE(Trace, "Add : Remote Mcast MAC " + std::string(mac) + + ", logical switch " + (ls ? std::string(ls) : "")); + if (entry) { + if (entry->mcast_remote_row_ != row) { + entry->old_mcast_remote_row_ = entry->mcast_remote_row_; + entry->mcast_remote_row_ = row; + if (entry->old_mcast_remote_row_ != NULL) + entry->OvsdbChange(); + } + } + } else { + assert(0); + } +} + +KSyncEntry *LogicalSwitchTable::Alloc(const KSyncEntry *key, uint32_t index) { + const LogicalSwitchEntry *k_entry = + static_cast(key); + LogicalSwitchEntry *entry = new LogicalSwitchEntry(this, k_entry); + return entry; +} + +KSyncEntry *LogicalSwitchTable::DBToKSyncEntry(const DBEntry* db_entry) { + const PhysicalDeviceVnEntry *entry = + static_cast(db_entry); + LogicalSwitchEntry *key = new LogicalSwitchEntry(this, entry); + return static_cast(key); +} + +OvsdbDBEntry *LogicalSwitchTable::AllocOvsEntry(struct ovsdb_idl_row *row) { + LogicalSwitchEntry key(this, row); + return static_cast(Create(&key)); +} + +///////////////////////////////////////////////////////////////////////////// +// Sandesh routines +///////////////////////////////////////////////////////////////////////////// +class LogicalSwitchSandeshTask : public Task { +public: + LogicalSwitchSandeshTask(std::string resp_ctx) : + Task((TaskScheduler::GetInstance()->GetTaskId("Agent::KSync")), -1), + resp_(new OvsdbLogicalSwitchResp()), resp_data_(resp_ctx) { + } + virtual ~LogicalSwitchSandeshTask() {} + virtual bool Run() { + std::vector lswitch; + TorAgentInit *init = + static_cast(Agent::GetInstance()->agent_init()); + OvsdbClientSession *session = init->ovsdb_client()->next_session(NULL); + LogicalSwitchTable *table = + session->client_idl()->logical_switch_table(); + LogicalSwitchEntry *entry = + static_cast(table->Next(NULL)); + while (entry != NULL) { + OvsdbLogicalSwitchEntry lentry; + lentry.set_state(entry->StateString()); + lentry.set_name(entry->name()); + lentry.set_physical_switch(entry->device_name()); + lentry.set_vxlan_id(entry->vxlan_id()); + lswitch.push_back(lentry); + entry = static_cast(table->Next(entry)); + } + resp_->set_lswitch(lswitch); + SendResponse(); + return true; + } +private: + void SendResponse() { + resp_->set_context(resp_data_); + resp_->set_more(false); + resp_->Response(); + } + + OvsdbLogicalSwitchResp *resp_; + std::string resp_data_; + DISALLOW_COPY_AND_ASSIGN(LogicalSwitchSandeshTask); +}; + +void OvsdbLogicalSwitchReq::HandleRequest() const { + LogicalSwitchSandeshTask *task = new LogicalSwitchSandeshTask(context()); + TaskScheduler *scheduler = TaskScheduler::GetInstance(); + scheduler->Enqueue(task); +} diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/logical_switch_ovsdb.h b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/logical_switch_ovsdb.h new file mode 100644 index 00000000000..4a0b0229fa3 --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/logical_switch_ovsdb.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +#ifndef SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_LOGICAL_SWITCH_OVSDB_H_ +#define SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_LOGICAL_SWITCH_OVSDB_H_ + +#include +#include +#include + +namespace AGENT { +class PhysicalDeviceVnEntry; +}; + +namespace OVSDB { +class LogicalSwitchTable : public OvsdbDBObject { +public: + LogicalSwitchTable(OvsdbClientIdl *idl, DBTable *table); + virtual ~LogicalSwitchTable(); + + void OvsdbNotify(OvsdbClientIdl::Op, struct ovsdb_idl_row *); + void OvsdbMcastLocalMacNotify(OvsdbClientIdl::Op, struct ovsdb_idl_row *); + void OvsdbMcastRemoteMacNotify(OvsdbClientIdl::Op, struct ovsdb_idl_row *); + + KSyncEntry *Alloc(const KSyncEntry *key, uint32_t index); + KSyncEntry *DBToKSyncEntry(const DBEntry*); + OvsdbDBEntry *AllocOvsEntry(struct ovsdb_idl_row *row); +private: + DISALLOW_COPY_AND_ASSIGN(LogicalSwitchTable); +}; + +class LogicalSwitchEntry : public OvsdbDBEntry { +public: + enum Trace { + ADD_REQ, + DEL_REQ, + ADD_ACK, + DEL_ACK, + }; + LogicalSwitchEntry(OvsdbDBObject *table, const char *name) : + OvsdbDBEntry(table), name_(name) {} + LogicalSwitchEntry(OvsdbDBObject *table, const LogicalSwitchEntry *key); + LogicalSwitchEntry(OvsdbDBObject *table, + const AGENT::PhysicalDeviceVnEntry *entry); + LogicalSwitchEntry(OvsdbDBObject *table, + struct ovsdb_idl_row *entry); + + Ip4Address &physical_switch_tunnel_ip(); + void AddMsg(struct ovsdb_idl_txn *); + void ChangeMsg(struct ovsdb_idl_txn *); + void DeleteMsg(struct ovsdb_idl_txn *); + + void OvsdbChange(); + + const std::string &name() const; + const std::string &device_name() const; + int64_t vxlan_id() const; + + bool Sync(DBEntry*); + bool IsLess(const KSyncEntry&) const; + std::string ToString() const {return "Logical Switch";} + KSyncEntry* UnresolvedReference(); +private: + void SendTrace(Trace event) const; + + friend class LogicalSwitchTable; + std::string name_; + std::string device_name_; + KSyncEntryPtr physical_switch_; + int64_t vxlan_id_; + struct ovsdb_idl_row *mcast_local_row_; + struct ovsdb_idl_row *mcast_remote_row_; + struct ovsdb_idl_row *old_mcast_remote_row_; + DISALLOW_COPY_AND_ASSIGN(LogicalSwitchEntry); +}; +}; + +#endif //SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_LOGICAL_SWITCH_OVSDB_H_ + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb.sandesh b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb.sandesh new file mode 100644 index 00000000000..538ecbf955a --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb.sandesh @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +/**************************************************************************** + Sandesh definitions for OVSDB Client + ****************************************************************************/ + +struct SandeshOvsdbClientSession { + 1: string status; +} + +struct SandeshOvsdbClient { + 1: string protocol; + 2: string server; + 3: i16 port; + 4: string tor_service_node; + 5: list sessions; +} + +response sandesh OvsdbClientResp { + 1: SandeshOvsdbClient client; +} + +request sandesh OvsdbClientReq { +} + +traceobject sandesh OvsdbTrace { + 1: string log; +} + +traceobject sandesh OvsdbError { + 1: string error; +} + +/**************************************************************************** + Sandesh definitions for Physical Switch. + ****************************************************************************/ + +struct OvsdbPhysicalSwitchEntry { + 1: string state; + 2: string name; + 3: string tunnel_ip; +} + +response sandesh OvsdbPhysicalSwitchResp { + 1: list pswitch; +} + +request sandesh OvsdbPhysicalSwitchReq { + 1: string session_remote_ip; + 2: i16 session_remote_port; +} + +struct SandeshPhysicalSwitchInfo { + 1: string op; + 2: string name; +} + +traceobject sandesh OvsdbPhysicalSwitch { + 1: SandeshPhysicalSwitchInfo p_switch; +} + +/**************************************************************************** + Sandesh definitions for Physical Port. + ****************************************************************************/ + +struct OvsdbPhysicalPortVlanInfo { + 1: i16 vlan; + 2: string logical_switch; + 3: i64 in_pkts; + 4: i64 in_bytes; + 5: i64 out_pkts; + 6: i64 out_bytes; +} + +struct OvsdbPhysicalPortEntry { + 1: string state; + 2: string name; + 3: list vlans; +} + +response sandesh OvsdbPhysicalPortResp { + 1: list port; +} + +request sandesh OvsdbPhysicalPortReq { + 1: string session_remote_ip; + 2: i16 session_remote_port; +} + +/**************************************************************************** + Sandesh definitions for Logical Switch. + ****************************************************************************/ + +struct OvsdbLogicalSwitchEntry { + 1: string state; + 2: string name; + 3: string physical_switch; + 4: i64 vxlan_id; +} + +response sandesh OvsdbLogicalSwitchResp { + 1: list lswitch; +} + +request sandesh OvsdbLogicalSwitchReq { + 1: string session_remote_ip; + 2: i16 session_remote_port; +} + +struct SandeshLogicalSwitchInfo { + 1: string op; + 2: string name; + 3: u64 vxlan; + 4: string device_name; +} + +traceobject sandesh OvsdbLogicalSwitch { + 1: SandeshLogicalSwitchInfo l_switch; +} + +/**************************************************************************** + Sandesh definitions for Vlan Port Bindings. + ****************************************************************************/ + +struct OvsdbVlanPortBindingEntry { + 1: string state; + 2: string physical_port; + 3: string physical_device; + 4: string logical_switch; + 5: u16 vlan; +} + +response sandesh OvsdbVlanPortBindingResp { + 1: list bindings; +} + +request sandesh OvsdbVlanPortBindingReq { + 1: string session_remote_ip; + 2: i16 session_remote_port; +} + +/**************************************************************************** + Sandesh definitions for Unicast Mac Local. + ****************************************************************************/ + +struct OvsdbUnicastMacLocalEntry { + 1: string state; + 2: string mac; + 3: string logical_switch; + 4: string dest_ip; +} + +response sandesh OvsdbUnicastMacLocalResp { + 1: list macs; +} + +request sandesh OvsdbUnicastMacLocalReq { + 1: string session_remote_ip; + 2: i16 session_remote_port; +} + +/**************************************************************************** + Sandesh definitions for Unicast Mac Remote. + ****************************************************************************/ + +struct OvsdbUnicastMacRemoteEntry { + 1: string state; + 2: string mac; + 3: string logical_switch; + 4: string dest_ip; + 5: bool self_exported; +} + +response sandesh OvsdbUnicastMacRemoteResp { + 1: list macs; +} + +request sandesh OvsdbUnicastMacRemoteReq { + 1: string session_remote_ip; + 2: i16 session_remote_port; +} +struct SandeshUnicastMacRemoteInfo { + 1: string op; + 2: string mac; + 3: string logical_switch; + 4: string dest_ip; +} + +traceobject sandesh OvsdbUnicastMacRemote { + 1: SandeshUnicastMacRemoteInfo ucast_remote; +} + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_client.cc b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_client.cc new file mode 100644 index 00000000000..06f60c39882 --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_client.cc @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +using OVSDB::OvsdbClient; + +OvsdbClient::OvsdbClient(OvsPeerManager *manager) : peer_manager_(manager), + ksync_obj_manager_(KSyncObjectManager::Init()){ +} + +OvsdbClient::~OvsdbClient() { +} + +KSyncObjectManager *OvsdbClient::ksync_obj_manager() { + return ksync_obj_manager_; +} + +void OvsdbClient::Init() { +} + +OvsdbClient *OvsdbClient::Allocate(Agent *agent, TorAgentParam *params, + OvsPeerManager *manager) { + KSyncObjectManager::Init(); + return (new OvsdbClientTcp(agent, params, manager)); +} + +///////////////////////////////////////////////////////////////////////////// +// Sandesh routines +///////////////////////////////////////////////////////////////////////////// +void OvsdbClientReq::HandleRequest() const { + OvsdbClientResp *resp = new OvsdbClientResp(); + SandeshOvsdbClient client_data; + TorAgentInit *init = + static_cast(Agent::GetInstance()->agent_init()); + OvsdbClient *client = init->ovsdb_client(); + client_data.set_protocol(client->protocol()); + client_data.set_server(client->server()); + client_data.set_port(client->port()); + client_data.set_tor_service_node(client->tsn_ip().to_string()); + client->AddSessionInfo(client_data); + resp->set_client(client_data); + resp->set_context(context()); + resp->set_more(false); + resp->Response(); +} + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_client.h b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_client.h new file mode 100644 index 00000000000..dbe931a72e0 --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_client.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +#ifndef SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVSDB_CLIENT_H_ +#define SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVSDB_CLIENT_H_ + +class TorAgentParam; +class SandeshOvsdbClient; + +class OvsPeerManager; +class KSyncObjectManager; + +namespace OVSDB { +class OvsdbClientSession; +class OvsdbClient { +public: + OvsdbClient(OvsPeerManager *manager); + virtual ~OvsdbClient(); + virtual void RegisterClients() = 0; + virtual const std::string protocol() = 0; + virtual const std::string server() = 0; + virtual uint16_t port() = 0; + virtual Ip4Address tsn_ip() = 0; + virtual OvsdbClientSession *next_session(OvsdbClientSession *session) = 0; + virtual void AddSessionInfo(SandeshOvsdbClient &client) = 0; + KSyncObjectManager *ksync_obj_manager(); + void Init(); + static OvsdbClient* Allocate(Agent *agent, TorAgentParam *params, + OvsPeerManager *manager); +protected: + OvsPeerManager *peer_manager_; +private: + KSyncObjectManager *ksync_obj_manager_; + DISALLOW_COPY_AND_ASSIGN(OvsdbClient); +}; +}; + +#endif //SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVSDB_CLIENT_H_ diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_client.sandesh b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_client.sandesh new file mode 100644 index 00000000000..e49cd11f4fd --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_client.sandesh @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +/**************************************************************************** + Sandesh definitions for OVSDB Client + ****************************************************************************/ + +struct OvsdbClientList { + 1: string protocol; + 2: string server; + 3: i16 port; + 4: list sessions (link=""); +} + +request sandesh OvsdbClientReq { +} + +request sandesh OvsdbClientSessionReq { +} + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_client_idl.cc b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_client_idl.cc new file mode 100644 index 00000000000..7d191a73c3f --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_client_idl.cc @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +#include +#include +#include +#include + +extern "C" { +#include +}; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +SandeshTraceBufferPtr OvsdbTraceBuf(SandeshTraceBufferCreate("Ovsdb", 5000)); +SandeshTraceBufferPtr OvsdbPktTraceBuf(SandeshTraceBufferCreate("Ovsdb Pkt", 5000)); + +namespace AGENT { +class PhysicalDeviceTable; +class PhysicalPortTable; +class LogicalPortTable; +class PhysicalDeviceVnTable; +} + +using OVSDB::OvsdbClientIdl; +using OVSDB::OvsdbClientSession; +using OVSDB::OvsdbEntryBase; +using OVSDB::VMInterfaceKSyncObject; +using OVSDB::PhysicalSwitchTable; +using OVSDB::LogicalSwitchTable; +using OVSDB::PhysicalPortTable; +using OVSDB::PhysicalLocatorTable; +using OVSDB::VlanPortBindingTable; +using OVSDB::UnicastMacLocalOvsdb; +using OVSDB::VrfOvsdbObject; + +namespace OVSDB { +void ovsdb_wrapper_idl_callback(void *idl_base, int op, + struct ovsdb_idl_row *row) { + OvsdbClientIdl *client_idl = (OvsdbClientIdl *) idl_base; + int i = ovsdb_wrapper_row_type(row); + if (i >= OvsdbClientIdl::OVSDB_TYPE_COUNT) + return; + if (client_idl->callback_[i] != NULL) + client_idl->callback_[i]((OvsdbClientIdl::Op)op, row); +} + +void ovsdb_wrapper_idl_txn_ack(void *idl_base, struct ovsdb_idl_txn *txn) { + OvsdbClientIdl *client_idl = (OvsdbClientIdl *) idl_base; + OvsdbEntryBase *entry = client_idl->pending_txn_[txn]; + bool success = ovsdb_wrapper_is_txn_success(txn); + if (!success) { + OVSDB_TRACE(Error, "Transaction failed: " + + std::string(ovsdb_wrapper_txn_get_error(txn))); + // we don't handle the case where txn fails, when entry is not present + // case of unicast_mac_remote entry. + assert(entry != NULL); + } + client_idl->DeleteTxn(txn); + if (entry) + entry->Ack(success); +} +}; + +OvsdbClientIdl::OvsdbClientIdl(OvsdbClientSession *session, Agent *agent, + OvsPeerManager *manager) : idl_(ovsdb_wrapper_idl_create()), + session_(session), agent_(agent), pending_txn_() { + vtep_global_= ovsdb_wrapper_vteprec_global_first(idl_); + ovsdb_wrapper_idl_set_callback(idl_, (void *)this, + ovsdb_wrapper_idl_callback, ovsdb_wrapper_idl_txn_ack); + parser_ = NULL; + for (int i = 0; i < OVSDB_TYPE_COUNT; i++) { + callback_[i] = NULL; + } + route_peer_.reset(manager->Allocate(IpAddress())); + vm_interface_table_.reset(new VMInterfaceKSyncObject(this, + (DBTable *)agent->interface_table())); + physical_switch_table_.reset(new PhysicalSwitchTable(this)); + logical_switch_table_.reset(new LogicalSwitchTable(this, + (DBTable *)agent->device_manager()->physical_device_vn_table())); + physical_port_table_.reset(new PhysicalPortTable(this)); + physical_locator_table_.reset(new PhysicalLocatorTable(this)); + vlan_port_table_.reset(new VlanPortBindingTable(this, + (DBTable *)agent->device_manager()->logical_port_table())); + unicast_mac_local_ovsdb_.reset(new UnicastMacLocalOvsdb(this, + route_peer())); + vrf_ovsdb_.reset(new VrfOvsdbObject(this, (DBTable *)agent->vrf_table())); +} + +OvsdbClientIdl::~OvsdbClientIdl() { + ovsdb_wrapper_idl_destroy(idl_); +} + +void OvsdbClientIdl::SendMointorReq() { + OVSDB_TRACE(Trace, "Sending Monitor Request"); + SendJsonRpc(ovsdb_wrapper_idl_encode_monitor_request(idl_)); +} + +void OvsdbClientIdl::SendJsonRpc(struct jsonrpc_msg *msg) { + struct json *json_msg = ovsdb_wrapper_jsonrpc_msg_to_json(msg); + char *s = ovsdb_wrapper_json_to_string(json_msg, 0); + ovsdb_wrapper_json_destroy(json_msg); + + session_->SendMsg((u_int8_t *)s, strlen(s)); +} + +void OvsdbClientIdl::MessageProcess(const u_int8_t *buf, std::size_t len) { + std::size_t used = 0; + // Multiple json message may be clubbed together, need to keep reading + // the buffer till whole message is consumed. + while (used != len) { + if (parser_ == NULL) { + parser_ = ovsdb_wrapper_json_parser_create(0); + } + const u_int8_t *pkt = buf + used; + std::size_t pkt_len = len - used; + std::size_t read; + read = ovsdb_wrapper_json_parser_feed(parser_, (const char *)pkt, + pkt_len); + OVSDB_PKT_TRACE(Trace, "Processed: " + std::string((const char *)pkt, read)); + used +=read; + + /* If we have complete JSON, attempt to parse it as JSON-RPC. */ + if (ovsdb_wrapper_json_parser_is_done(parser_)) { + struct json *json = ovsdb_wrapper_json_parser_finish(parser_); + parser_ = NULL; + struct jsonrpc_msg *msg; + char *error = ovsdb_wrapper_jsonrpc_msg_from_json(json, &msg); + if (error) { + assert(0); + free(error); + //continue; + } + + if (ovsdb_wrapper_msg_echo_req(msg)) { + /* Echo request. Send reply. */ + struct jsonrpc_msg *reply; + reply = ovsdb_wrapper_jsonrpc_create_reply(msg); + SendJsonRpc(reply); + //jsonrpc_session_send(s, reply); + } else if (ovsdb_wrapper_msg_echo_reply(msg)) { + /* It's a reply to our echo request. Suppress it. */ + } else { + ovsdb_wrapper_idl_msg_process(idl_, msg); + continue; + } + ovsdb_wrapper_jsonrpc_msg_destroy(msg); + } + } +} + +struct ovsdb_idl_txn *OvsdbClientIdl::CreateTxn(OvsdbEntryBase *entry) { + struct ovsdb_idl_txn *txn = ovsdb_wrapper_idl_txn_create(idl_); + pending_txn_[txn] = entry; + return txn; +} + +void OvsdbClientIdl::DeleteTxn(struct ovsdb_idl_txn *txn) { + pending_txn_.erase(txn); + ovsdb_wrapper_idl_txn_destroy(txn); +} + +Ip4Address OvsdbClientIdl::tsn_ip() { + return session_->tsn_ip(); +} + +KSyncObjectManager *OvsdbClientIdl::ksync_obj_manager() { + return session_->ksync_obj_manager(); +} + +OvsPeer *OvsdbClientIdl::route_peer() { + return route_peer_.get(); +} + +VMInterfaceKSyncObject *OvsdbClientIdl::vm_interface_table() { + return vm_interface_table_.get(); +} + +PhysicalSwitchTable *OvsdbClientIdl::physical_switch_table() { + return physical_switch_table_.get(); +} + +LogicalSwitchTable *OvsdbClientIdl::logical_switch_table() { + return logical_switch_table_.get(); +} + +PhysicalPortTable *OvsdbClientIdl::physical_port_table() { + return physical_port_table_.get(); +} + +PhysicalLocatorTable *OvsdbClientIdl::physical_locator_table() { + return physical_locator_table_.get(); +} + +VlanPortBindingTable *OvsdbClientIdl::vlan_port_table() { + return vlan_port_table_.get(); +} + +UnicastMacLocalOvsdb *OvsdbClientIdl::unicast_mac_local_ovsdb() { + return unicast_mac_local_ovsdb_.get(); +} + +VrfOvsdbObject *OvsdbClientIdl::vrf_ovsdb() { + return vrf_ovsdb_.get(); +} + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_client_idl.h b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_client_idl.h new file mode 100644 index 00000000000..955a85720a8 --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_client_idl.h @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +#ifndef SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVSDB_CLIENT_IDL_H_ +#define SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVSDB_CLIENT_IDL_H_ + +#include + +#include +#include +#include + +extern SandeshTraceBufferPtr OvsdbTraceBuf; +extern SandeshTraceBufferPtr OvsdbPktTraceBuf; + +#define OVSDB_TRACE(obj, ...)\ +do {\ + Ovsdb##obj::TraceMsg(OvsdbTraceBuf, __FILE__, __LINE__, __VA_ARGS__);\ +} while(false); + +#define OVSDB_PKT_TRACE(obj, ...)\ +do {\ + Ovsdb##obj::TraceMsg(OvsdbPktTraceBuf, __FILE__, __LINE__, __VA_ARGS__);\ +} while(false); + +class OvsPeer; +class OvsPeerManager; +class KSyncObjectManager; + +namespace OVSDB { +class OvsdbClientSession; +class VMInterfaceKSyncObject; +class PhysicalSwitchTable; +class LogicalSwitchTable; +class PhysicalPortTable; +class PhysicalLocatorTable; +class VlanPortBindingTable; +class PhysicalLocatorTable; +class UnicastMacLocalOvsdb; +class VrfOvsdbObject; +class OvsdbEntryBase; + +class OvsdbClientIdl { +public: + enum Op { + OVSDB_DEL = 0, + OVSDB_ADD, + OVSDB_INVALID_OP + }; + + enum EntryType { + OVSDB_PHYSICAL_SWITCH = 0, + OVSDB_LOGICAL_SWITCH, + OVSDB_PHYSICAL_PORT, + OVSDB_PHYSICAL_LOCATOR, + OVSDB_UCAST_MAC_LOCAL, + OVSDB_UCAST_MAC_REMOTE, + OVSDB_PHYSICAL_LOCATOR_SET, + OVSDB_MCAST_MAC_LOCAL, + OVSDB_MCAST_MAC_REMOTE, + OVSDB_TYPE_COUNT + }; + typedef boost::function NotifyCB; + typedef std::map PendingTxnMap; + + OvsdbClientIdl(OvsdbClientSession *session, Agent *agent, OvsPeerManager *manager); + virtual ~OvsdbClientIdl(); + + // Send request to start monitoring OVSDB server + void SendMointorReq(); + // Send encode json rpc messgage to OVSDB server + void SendJsonRpc(struct jsonrpc_msg *msg); + // Process the recevied message and trigger update to ovsdb client + void MessageProcess(const u_int8_t *buf, std::size_t len); + // Create a OVSDB transaction to start encoding an update + struct ovsdb_idl_txn *CreateTxn(OvsdbEntryBase *entry); + // Delete the OVSDB transaction + void DeleteTxn(struct ovsdb_idl_txn *txn); + void Register(EntryType type, NotifyCB cb) {callback_[type] = cb;} + void UnRegister(EntryType type) {callback_[type] = NULL;} + // Get TOR Service Node IP + Ip4Address tsn_ip(); + + KSyncObjectManager *ksync_obj_manager(); + OvsPeer *route_peer(); + Agent *agent() {return agent_;} + VMInterfaceKSyncObject *vm_interface_table(); + PhysicalSwitchTable *physical_switch_table(); + LogicalSwitchTable *logical_switch_table(); + PhysicalPortTable *physical_port_table(); + PhysicalLocatorTable *physical_locator_table(); + VlanPortBindingTable *vlan_port_table(); + UnicastMacLocalOvsdb *unicast_mac_local_ovsdb(); + VrfOvsdbObject *vrf_ovsdb(); + +private: + friend void ovsdb_wrapper_idl_callback(void *, int, struct ovsdb_idl_row *); + friend void ovsdb_wrapper_idl_txn_ack(void *, struct ovsdb_idl_txn *); + + struct ovsdb_idl *idl_; + struct json_parser * parser_; + const struct vteprec_global *vtep_global_; + OvsdbClientSession *session_; + Agent *agent_; + NotifyCB callback_[OVSDB_TYPE_COUNT]; + PendingTxnMap pending_txn_; + std::auto_ptr route_peer_; + std::auto_ptr vm_interface_table_; + std::auto_ptr physical_switch_table_; + std::auto_ptr logical_switch_table_; + std::auto_ptr physical_port_table_; + std::auto_ptr physical_locator_table_; + std::auto_ptr vlan_port_table_; + std::auto_ptr unicast_mac_local_ovsdb_; + std::auto_ptr vrf_ovsdb_; + DISALLOW_COPY_AND_ASSIGN(OvsdbClientIdl); +}; +}; // namespace OVSDB + +#endif // SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVSDB_CLIENT_IDL_H_ + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_client_session.cc b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_client_session.cc new file mode 100644 index 00000000000..6a6566025b7 --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_client_session.cc @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +#include + +#include +#include +#include +#include +#include + +#include + +using OVSDB::OvsdbClientIdl; +using OVSDB::OvsdbClientSession; + +OvsdbClientSession::OvsdbClientSession(Agent *agent, OvsPeerManager *manager) : + client_idl_(this, agent, manager), agent_(agent) { +} + +OvsdbClientSession::~OvsdbClientSession() { +} + +void OvsdbClientSession::MessageProcess(const u_int8_t *buf, std::size_t len) { + client_idl_.MessageProcess(buf, len); +} + +void OvsdbClientSession::OnEstablish() { + OVSDB_TRACE(Trace, "Connection to client established"); + client_idl_.SendMointorReq(); +} + +void OvsdbClientSession::OnClose() { + OVSDB_TRACE(Trace, "Connection to client Closed"); + assert(0); +} + +OvsdbClientIdl *OvsdbClientSession::client_idl() { + return &client_idl_; +} + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_client_session.h b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_client_session.h new file mode 100644 index 00000000000..0595c659315 --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_client_session.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +#ifndef SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVSDB_CLIENT_SESSION_H_ +#define SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVSDB_CLIENT_SESSION_H_ + +#include + +#include +#include + +class OvsPeer; +class OvsPeerManager; +class KSyncObjectManager; + +namespace OVSDB { +class OvsdbClientIdl; +class OvsdbClientSession { +public: + OvsdbClientSession(Agent *agent, OvsPeerManager *manager); + virtual ~OvsdbClientSession(); + + virtual KSyncObjectManager *ksync_obj_manager() = 0; + virtual Ip4Address tsn_ip() = 0; + virtual void SendMsg(u_int8_t *buf, std::size_t len) = 0; + void MessageProcess(const u_int8_t *buf, std::size_t len); + void OnEstablish(); + void OnClose(); + OvsdbClientIdl *client_idl(); + +private: + friend class OvsdbClientIdl; + OvsdbClientIdl client_idl_; + Agent *agent_; + DISALLOW_COPY_AND_ASSIGN(OvsdbClientSession); +}; +}; // namespace OVSDB + +#endif // SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVSDB_CLIENT_SESSION_H_ + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_client_tcp.cc b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_client_tcp.cc new file mode 100644 index 00000000000..f594c17c534 --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_client_tcp.cc @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +#include + +#include +#include +#include + +#include + +using OVSDB::OvsdbClientSession; +using OVSDB::OvsdbClientTcp; +using OVSDB::OvsdbClientTcpSession; +using OVSDB::OvsdbClientTcpSessionReader; + +OvsdbClientTcp::OvsdbClientTcp(Agent *agent, TorAgentParam *params, + OvsPeerManager *manager) : TcpServer(agent->event_manager()), + OvsdbClient(manager), agent_(agent), session_(NULL), + server_ep_(IpAddress(params->tor_ip()), params->tor_port()), + tsn_ip_(params->tsn_ip()) { +} + +OvsdbClientTcp::~OvsdbClientTcp() { +} + +void OvsdbClientTcp::RegisterClients() { + session_ = CreateSession(); + Connect(session_, server_ep_); +} + +TcpSession *OvsdbClientTcp::AllocSession(Socket *socket) { + TcpSession *session = new OvsdbClientTcpSession(agent_, peer_manager_, + this, socket); + session->set_observer(boost::bind(&OvsdbClientTcp::OnSessionEvent, + this, _1, _2)); + return session; +} + +void OvsdbClientTcp::OnSessionEvent(TcpSession *session, + TcpSession::Event event) { + OvsdbClientTcpSession *tcp = static_cast(session); + boost::system::error_code ec; + switch (event) { + case TcpSession::CONNECT_FAILED: + /* Failed to Connect, Try Again! */ + Connect(session_, server_ep_); + tcp->set_status("Reconnect"); + break; + case TcpSession::CLOSE: + /* TODO need to handle reconnects */ + tcp->OnClose(); + break; + case TcpSession::CONNECT_COMPLETE: + ec = tcp->SetSocketOptions(); + assert(ec.value() == 0); + tcp->set_status("Established"); + tcp->OnEstablish(); + break; + default: + break; + } +} + +const std::string OvsdbClientTcp::protocol() { + return "TCP"; +} + +const std::string OvsdbClientTcp::server() { + return server_ep_.address().to_string(); +} + +uint16_t OvsdbClientTcp::port() { + return server_ep_.port(); +} + +Ip4Address OvsdbClientTcp::tsn_ip() { + return tsn_ip_; +} + +OvsdbClientSession *OvsdbClientTcp::next_session(OvsdbClientSession *session) { + return static_cast( + static_cast(session_)); +} + +void OvsdbClientTcp::AddSessionInfo(SandeshOvsdbClient &client){ + SandeshOvsdbClientSession session; + std::vector session_list; + OvsdbClientTcpSession *tcp = static_cast(session_); + session.set_status(tcp->status()); + session_list.push_back(session); + client.set_sessions(session_list); +} + +OvsdbClientTcpSession::OvsdbClientTcpSession(Agent *agent, + OvsPeerManager *manager, TcpServer *server, Socket *sock, + bool async_ready) : OvsdbClientSession(agent, manager), + TcpSession(server, sock, async_ready), status_("Init") { + reader_ = new OvsdbClientTcpSessionReader(this, + boost::bind(&OvsdbClientTcpSession::RecvMsg, this, _1, _2)); + /* + * Process the received messages in a KSync workqueue task context, + * to assure only one thread is writting data to OVSDB client. + */ + receive_queue_ = new WorkQueue( + TaskScheduler::GetInstance()->GetTaskId("Agent::KSync"), -1, + boost::bind(&OvsdbClientTcpSession::ReceiveDequeue, this, _1)); +} + +OvsdbClientTcpSession::~OvsdbClientTcpSession() { + delete reader_; + receive_queue_->Shutdown(); + delete receive_queue_; +} + +void OvsdbClientTcpSession::OnRead(Buffer buffer) { + reader_->OnRead(buffer); +} + +void OvsdbClientTcpSession::SendMsg(u_int8_t *buf, std::size_t len) { + OVSDB_PKT_TRACE(Trace, "Sending: " + std::string((char *)buf, len)); + Send(buf, len, NULL); +} + +void OvsdbClientTcpSession::RecvMsg(const u_int8_t *buf, std::size_t len) { + OVSDB_PKT_TRACE(Trace, "Received: " + std::string((const char*)buf, len)); + queue_msg msg; + msg.buf = (u_int8_t *)malloc(len); + memcpy(msg.buf, buf, len); + msg.len = len; + receive_queue_->Enqueue(msg); +} + +bool OvsdbClientTcpSession::ReceiveDequeue(queue_msg msg) { + MessageProcess(msg.buf, msg.len); + free(msg.buf); + return true; +} + +KSyncObjectManager *OvsdbClientTcpSession::ksync_obj_manager() { + OvsdbClientTcp *ovs_server = static_cast(server()); + return ovs_server->ksync_obj_manager(); +} + +Ip4Address OvsdbClientTcpSession::tsn_ip() { + OvsdbClientTcp *ovs_server = static_cast(server()); + return ovs_server->tsn_ip(); +} + +OvsdbClientTcpSessionReader::OvsdbClientTcpSessionReader( + TcpSession *session, ReceiveCallback callback) : + TcpMessageReader(session, callback) { +} + +OvsdbClientTcpSessionReader::~OvsdbClientTcpSessionReader() { +} + +int OvsdbClientTcpSessionReader::MsgLength(Buffer buffer, int offset) { + size_t size = TcpSession::BufferSize(buffer); + int remain = size - offset; + if (remain < GetHeaderLenSize()) { + return -1; + } + + return remain; +} + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_client_tcp.h b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_client_tcp.h new file mode 100644 index 00000000000..889d5ace444 --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_client_tcp.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ +#ifndef SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVSDB_CLIENT_TCP_H_ +#define SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVSDB_CLIENT_TCP_H_ +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace OVSDB { +class OvsdbClientTcpSessionReader : public TcpMessageReader { +public: + OvsdbClientTcpSessionReader(TcpSession *session, ReceiveCallback callback); + virtual ~OvsdbClientTcpSessionReader(); + +protected: + virtual int MsgLength(Buffer buffer, int offset); + + virtual const int GetHeaderLenSize() { + // We don't have any header + return 0; + } + + virtual const int GetMaxMessageSize() { + return kMaxMessageSize; + } + +private: + static const int kMaxMessageSize = 4096; + DISALLOW_COPY_AND_ASSIGN(OvsdbClientTcpSessionReader); +}; + +class OvsdbClientTcpSession : public OvsdbClientSession, public TcpSession { +public: + struct queue_msg { + u_int8_t *buf; + std::size_t len; + }; + OvsdbClientTcpSession(Agent *agent, OvsPeerManager *manager, + TcpServer *server, Socket *sock, bool async_ready = true); + ~OvsdbClientTcpSession(); + + // Send message to OVSDB server + void SendMsg(u_int8_t *buf, std::size_t len); + // Receive message from OVSDB server + void RecvMsg(const u_int8_t *buf, std::size_t len); + // Dequeue received message from workqueue for processing + bool ReceiveDequeue(queue_msg msg); + + KSyncObjectManager *ksync_obj_manager(); + Ip4Address tsn_ip(); + + void set_status(std::string status) {status_ = status;} + std::string status() {return status_;} + +protected: + virtual void OnRead(Buffer buffer); +private: + std::string status_; + OvsdbClientTcpSessionReader *reader_; + WorkQueue *receive_queue_; + DISALLOW_COPY_AND_ASSIGN(OvsdbClientTcpSession); +}; + +class OvsdbClientTcp : public TcpServer, public OvsdbClient { +public: + OvsdbClientTcp(Agent *agent, TorAgentParam *params, + OvsPeerManager *manager); + virtual ~OvsdbClientTcp(); + + virtual TcpSession *AllocSession(Socket *socket); + void RegisterClients(); + void OnSessionEvent(TcpSession *session, TcpSession::Event event); + const std::string protocol(); + const std::string server(); + uint16_t port(); + Ip4Address tsn_ip(); + OvsdbClientSession *next_session(OvsdbClientSession *session); + void AddSessionInfo(SandeshOvsdbClient &client); +private: + friend class OvsdbClientTcpSession; + Agent *agent_; + TcpSession *session_; + boost::asio::ip::tcp::endpoint server_ep_; + Ip4Address tsn_ip_; + DISALLOW_COPY_AND_ASSIGN(OvsdbClientTcp); +}; +}; + +#endif //SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVSDB_CLIENT_TCP_H_ + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_entry.cc b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_entry.cc new file mode 100644 index 00000000000..b4be56e53a4 --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_entry.cc @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ +extern "C" { +#include +} +#include +#include +#include + +using OVSDB::OvsdbEntry; +using OVSDB::OvsdbDBEntry; +using OVSDB::OvsdbObject; +using OVSDB::OvsdbDBObject; + +OvsdbEntry::OvsdbEntry(OvsdbObject *table) : KSyncEntry(), table_(table) { +} + +OvsdbEntry::OvsdbEntry(OvsdbObject *table, uint32_t index) : KSyncEntry(index), + table_(table) { +} + +OvsdbEntry::~OvsdbEntry() { +} + +bool OvsdbEntry::Add() { + return true; +} + +bool OvsdbEntry::Change() { + return true; +} + +bool OvsdbEntry::Delete() { + return true; +} + +KSyncObject *OvsdbEntry::GetObject() { + return table_; +} + +void OvsdbEntry::Ack(bool success) { +} + +OvsdbDBEntry::OvsdbDBEntry(OvsdbDBObject *table) : KSyncDBEntry(), table_(table), + ovs_entry_(NULL) { +} + +OvsdbDBEntry::OvsdbDBEntry(OvsdbDBObject *table, struct ovsdb_idl_row *ovs_entry) : KSyncDBEntry(), + table_(table), ovs_entry_(ovs_entry) { +} + +OvsdbDBEntry::~OvsdbDBEntry() { +} + +bool OvsdbDBEntry::Add() { + PreAddChange(); + OvsdbDBObject *object = static_cast(GetObject()); + struct ovsdb_idl_txn *txn = object->client_idl_->CreateTxn(this); + AddMsg(txn); + struct jsonrpc_msg *msg = ovsdb_wrapper_idl_txn_encode(txn); + if (msg == NULL) { + object->client_idl()->DeleteTxn(txn); + return true; + } + object->client_idl_->SendJsonRpc(msg); + return false; +} + +bool OvsdbDBEntry::Change() { + PreAddChange(); + OvsdbDBObject *object = static_cast(GetObject()); + struct ovsdb_idl_txn *txn = object->client_idl_->CreateTxn(this); + ChangeMsg(txn); + struct jsonrpc_msg *msg = ovsdb_wrapper_idl_txn_encode(txn); + if (msg == NULL) { + object->client_idl()->DeleteTxn(txn); + return true; + } + object->client_idl_->SendJsonRpc(msg); + return false; +} + +bool OvsdbDBEntry::Delete() { + OvsdbDBObject *object = static_cast(GetObject()); + struct ovsdb_idl_txn *txn = object->client_idl_->CreateTxn(this); + DeleteMsg(txn); + struct jsonrpc_msg *msg = ovsdb_wrapper_idl_txn_encode(txn); + PostDelete(); + if (msg == NULL) { + object->client_idl()->DeleteTxn(txn); + return true; + } + object->client_idl_->SendJsonRpc(msg); + return false; +} + +bool OvsdbDBEntry::IsDataResolved() { + return (ovs_entry_ == NULL) ? false : true; +} + +bool OvsdbDBEntry::IsDelAckWaiting() { + KSyncState state = GetState(); + return (state >= DEL_DEFER_DEL_ACK && state <= RENEW_WAIT); +} + +bool OvsdbDBEntry::IsAddChangeAckWaiting() { + KSyncState state = GetState(); + return (state == SYNC_WAIT || state == NEED_SYNC || + state == DEL_DEFER_SYNC); +} + +void OvsdbDBEntry::NotifyAdd(struct ovsdb_idl_row *row) { + ovs_entry_ = row; + OvsdbChange(); +} + +void OvsdbDBEntry::NotifyDelete() { + ovs_entry_ = NULL; +} + +KSyncObject *OvsdbDBEntry::GetObject() { + return table_; +} + +void OvsdbDBEntry::Ack(bool success) { + OvsdbDBObject *object = static_cast(GetObject()); + // TODO we are not retrying as of now, + // success = true; + if (success) { + if (IsDelAckWaiting()) + object->NotifyEvent(this, KSyncEntry::DEL_ACK); + else if (IsAddChangeAckWaiting()) + object->NotifyEvent(this, KSyncEntry::ADD_ACK); + else + delete this; + } else { + // On Failure try again + if (IsDelAckWaiting()) { + OVSDB_TRACE(Error, "Delete Transaction failed for " + ToString()); + //object->NotifyEvent(this, KSyncEntry::DEL_ACK); + // if we are waiting to renew, dont retry delete. + if (GetState() != RENEW_WAIT) { + Delete(); + } else { + object->NotifyEvent(this, KSyncEntry::DEL_ACK); + } + } else if (IsAddChangeAckWaiting()) { + OVSDB_TRACE(Error, "Add Transaction failed for " + ToString()); + //object->NotifyEvent(this, KSyncEntry::ADD_ACK); + // if we are waiting to delete, dont retry add. + if (GetState() != DEL_DEFER_SYNC) { + Add(); + } else { + object->NotifyEvent(this, KSyncEntry::ADD_ACK); + } + } else { + OVSDB_TRACE(Error, "Ovsdb Delete Transaction failed for " + ToString()); + object->OvsdbNotify(OvsdbClientIdl::OVSDB_ADD, ovs_entry_); + delete this; + //Delete(); + } + } +} diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_entry.h b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_entry.h new file mode 100644 index 00000000000..0cae512595f --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_entry.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +#ifndef SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVSDB_ENTRY_H_ +#define SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVSDB_ENTRY_H_ + +#include + +#include +#include + +class KSyncObject; + +namespace OVSDB { +class OvsdbObject; +class OvsdbDBObject; + +class OvsdbEntryBase { +public: + virtual void Ack(bool success) = 0; +}; + +class OvsdbEntry : public KSyncEntry, public OvsdbEntryBase { +public: + OvsdbEntry(OvsdbObject *table); + OvsdbEntry(OvsdbObject *table, uint32_t index); + virtual ~OvsdbEntry(); + + virtual bool Add(); + virtual bool Change(); + virtual bool Delete(); + + struct ovsdb_idl_row *ovs_entry() {return ovs_entry_;} + KSyncObject* GetObject(); + void Ack(bool success); +protected: + OvsdbObject *table_; + struct ovsdb_idl_row *ovs_entry_; +private: + DISALLOW_COPY_AND_ASSIGN(OvsdbEntry); +}; + +class OvsdbDBEntry : public KSyncDBEntry, public OvsdbEntryBase { +public: + OvsdbDBEntry(OvsdbDBObject *table); + OvsdbDBEntry(OvsdbDBObject *table, struct ovsdb_idl_row *ovs_entry); + virtual ~OvsdbDBEntry(); + + // pre processing callback for add/change msg to take object reference + virtual void PreAddChange() {} + // post processing callback for delete msg to release object reference + virtual void PostDelete() {} + // Encode add message for entry + virtual void AddMsg(struct ovsdb_idl_txn *) = 0; + // Encode change message for entry + virtual void ChangeMsg(struct ovsdb_idl_txn *) = 0; + // Encode delete message for entry + virtual void DeleteMsg(struct ovsdb_idl_txn *) = 0; + + virtual void OvsdbChange() {} + + bool AllowDeleteStateComp() {return false;} + virtual void NotifyAdd(struct ovsdb_idl_row *); + virtual void NotifyDelete(); + + bool Add(); + bool Change(); + bool Delete(); + + virtual bool IsDataResolved(); + bool IsDelAckWaiting(); + bool IsAddChangeAckWaiting(); + + struct ovsdb_idl_row *ovs_entry() {return ovs_entry_;} + void clear_ovs_entry() {ovs_entry_ = NULL;} + + KSyncObject* GetObject(); + void Ack(bool success); +protected: + OvsdbDBObject *table_; + struct ovsdb_idl_row *ovs_entry_; +private: + friend class OvsdbDBObject; + DISALLOW_COPY_AND_ASSIGN(OvsdbDBEntry); +}; +}; + +#endif //SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVSDB_ENTRY_H_ + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_object.cc b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_object.cc new file mode 100644 index 00000000000..37d1295ff85 --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_object.cc @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +extern "C" { +#include +}; + +#include +#include + +using OVSDB::OvsdbObject; +using OVSDB::OvsdbDBObject; +using OVSDB::OvsdbDBEntry; + +OvsdbObject::OvsdbObject(OvsdbClientIdl *idl) : KSyncObject(), + client_idl_(idl) { +} + +OvsdbObject::~OvsdbObject() { +} + +KSyncEntry *OvsdbObject::FindActiveEntry(KSyncEntry *key) { + KSyncEntry *entry = Find(key); + if (entry != NULL && entry->GetState() != KSyncEntry::TEMP && + !entry->IsDeleted()) { + return entry; + } + return NULL; +} + +OvsdbDBObject::OvsdbDBObject(OvsdbClientIdl *idl) : KSyncDBObject(), + client_idl_(idl), walkid_(DBTableWalker::kInvalidWalkerId) { +} + +OvsdbDBObject::OvsdbDBObject(OvsdbClientIdl *idl, DBTable *tbl) : + KSyncDBObject(tbl), client_idl_(idl), + walkid_(DBTableWalker::kInvalidWalkerId) { + DBTableWalker *walker = client_idl_->agent()->db()->GetWalker(); + // Start a walker to get the entries which were already present, + // when we register to the DB Table + walkid_ = walker->WalkTable(tbl, NULL, + boost::bind(&OvsdbDBObject::DBWalkNotify, this, _1, _2), + boost::bind(&OvsdbDBObject::DBWalkDone, this, _1)); +} + +OvsdbDBObject::~OvsdbDBObject() { + if (walkid_ != DBTableWalker::kInvalidWalkerId) { + DBTableWalker *walker = client_idl_->agent()->db()->GetWalker(); + walker->WalkCancel(walkid_); + } +} + +void OvsdbDBObject::NotifyAddOvsdb(OvsdbDBEntry *key, struct ovsdb_idl_row *row) { + OvsdbDBEntry *entry = static_cast(Find(key)); + if (entry) { + if (entry->IsAddChangeAckWaiting()) { + entry->NotifyAdd(row); + } + } else { + //TODO trigger delete of this entry + OvsdbDBEntry *del_entry = AllocOvsEntry(row); + del_entry->ovs_entry_ = row; + Delete(del_entry); + //del_entry->Delete(); + //delete del_entry; + } +} + +void OvsdbDBObject::NotifyDeleteOvsdb(OvsdbDBEntry *key) { + OvsdbDBEntry *entry = static_cast(Find(key)); + if (entry) { + if (entry->IsDelAckWaiting()) { + entry->NotifyDelete(); + } else { + // Clear OVS State and trigger Add/Change Req on entry + entry->clear_ovs_entry(); + NotifyEvent(entry, KSyncEntry::ADD_CHANGE_REQ); + } + } +} + +bool OvsdbDBObject::DBWalkNotify(DBTablePartBase *part, DBEntryBase *entry) { + Notify(part, entry); + return true; +} + +void OvsdbDBObject::DBWalkDone(DBTableBase *partition) { + walkid_ = DBTableWalker::kInvalidWalkerId; +} + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_object.h b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_object.h new file mode 100644 index 00000000000..4d88a7eb657 --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_object.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +#ifndef SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVSDB_OBJECT_H_ +#define SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVSDB_OBJECT_H_ + +#include + +#include +#include +#include +#include + +#include + +namespace OVSDB { +class OvsdbDBEntry; + +class OvsdbObject : public KSyncObject { +public: + OvsdbObject(OvsdbClientIdl *idl); + virtual ~OvsdbObject(); + + KSyncEntry *FindActiveEntry(KSyncEntry *key); + OvsdbClientIdl *client_idl() { return client_idl_;} +protected: + OvsdbClientIdl *client_idl_; +private: + DISALLOW_COPY_AND_ASSIGN(OvsdbObject); +}; + +class OvsdbDBObject : public KSyncDBObject { +public: + OvsdbDBObject(OvsdbClientIdl *idl); + OvsdbDBObject(OvsdbClientIdl *idl, DBTable *tbl); + virtual ~OvsdbDBObject(); + + void NotifyAddOvsdb(OvsdbDBEntry *key, struct ovsdb_idl_row *row); + void NotifyDeleteOvsdb(OvsdbDBEntry *key); + + virtual void OvsdbNotify(OvsdbClientIdl::Op, struct ovsdb_idl_row *) = 0; + virtual OvsdbDBEntry *AllocOvsEntry(struct ovsdb_idl_row *row) = 0; + bool DBWalkNotify(DBTablePartBase *partition, DBEntryBase *entry); + void DBWalkDone(DBTableBase *partition); + + OvsdbClientIdl *client_idl() { return client_idl_;} +protected: + OvsdbClientIdl *client_idl_; +private: + friend class OvsdbDBEntry; + DBTableWalker::WalkId walkid_; + DISALLOW_COPY_AND_ASSIGN(OvsdbDBObject); +}; +}; + +#endif //SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVSDB_OBJECT_H_ + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_route_data.cc b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_route_data.cc new file mode 100644 index 00000000000..d58cbba4128 --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_route_data.cc @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +#include + +#include +#include +#include +#include + +#include +#include + +using namespace std; +using namespace boost::asio; + +OvsdbRouteData::OvsdbRouteData(const Peer *peer, uint32_t vxlan_id, + const Ip4Address &tor_ip, + const Ip4Address &router_id, + const std::string &tor_vrf, + const std::string &dest_vn_name) : + AgentRouteData(false), peer_(peer), vxlan_id_(vxlan_id), tor_ip_(tor_ip), + tor_vrf_(tor_vrf), router_id_(router_id), dest_vn_name_(dest_vn_name) { +} + +OvsdbRouteData::OvsdbRouteData(const Peer *peer) : + AgentRouteData(false), peer_(peer), vxlan_id_() { +} + +OvsdbRouteData::~OvsdbRouteData() { +} + +std::string OvsdbRouteData::ToString() const { + return "OVS Route Data"; +} + +bool OvsdbRouteData::AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *data) { + bool ret = false; + NextHop *nh = NULL; + + if (path->vxlan_id() != vxlan_id_) { + path->set_vxlan_id(vxlan_id_); + ret = true; + } + + if (path->dest_vn_name() != dest_vn_name_) { + path->set_dest_vn_name(dest_vn_name_); + ret = true; + } + + SecurityGroupList sg_list; + if (path->sg_list() != sg_list) { + path->set_sg_list(sg_list); + ret = true; + } + + // Create Tunnel-NH first + TunnelType::Type type = TunnelType::ComputeType(TunnelType::VxlanType()); + DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE); + nh_req.key.reset(new TunnelNHKey(tor_vrf_, router_id_, tor_ip_, false, + type)); + nh_req.data.reset(new TunnelNHData()); + agent->nexthop_table()->Process(nh_req); + + // Get the NH + TunnelNHKey key(tor_vrf_, router_id_, tor_ip_, false, type); + nh = static_cast(agent->nexthop_table()->FindActiveEntry(&key)); + + path->set_tunnel_bmap(TunnelType::VxlanType()); + path->set_tunnel_type(TunnelType::ComputeType(path->tunnel_bmap())); + + path->set_unresolved(false); + if (path->ChangeNH(agent, nh) == true) + ret = true; + + return ret; +} diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_route_data.h b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_route_data.h new file mode 100644 index 00000000000..a7917892e47 --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_route_data.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ +#ifndef SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVS_ROUTE_H_ +#define SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVS_ROUTE_H_ + +#include +#include + +class Peer; + +class OvsdbRouteData : public AgentRouteData { +public: + OvsdbRouteData(const Peer *peer, uint32_t vxlan_id, + const Ip4Address &tor_ip, const Ip4Address &router_id, + const std::string &tor_vrf, const std::string &dest_vn_name); + OvsdbRouteData(const Peer *peer); + virtual ~OvsdbRouteData(); + + virtual std::string ToString() const; + virtual bool AddChangePath(Agent *agent, AgentPath *path, + const AgentRoute *data); + +private: + const Peer *peer_; + uint32_t vxlan_id_; + Ip4Address tor_ip_; + std::string tor_vrf_; + Ip4Address router_id_; + std::string dest_vn_name_; + DISALLOW_COPY_AND_ASSIGN(OvsdbRouteData); +}; + +#endif // SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVS_ROUTE_H_ diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_route_peer.cc b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_route_peer.cc new file mode 100644 index 00000000000..87cb67fd330 --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_route_peer.cc @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ +#include +#include + +#include +#include + +OvsPeer::OvsPeer(const IpAddress &peer_ip, uint64_t gen_id, + OvsPeerManager *peer_manager) : + Peer(Peer::OVS_PEER, "OVS-" + peer_ip.to_string(), true), peer_ip_(peer_ip), + gen_id_(gen_id), peer_manager_(peer_manager) { +} + +OvsPeer::~OvsPeer() { +} + +bool OvsPeer::Compare(const Peer *rhs) const { + const OvsPeer *rhs_peer = static_cast(rhs); + if (gen_id_ != rhs_peer->gen_id_) + return gen_id_ < rhs_peer->gen_id_; + + return peer_ip_ < rhs_peer->peer_ip_; +} + +bool OvsPeer::AddOvsRoute(const boost::uuids::uuid &vn_uuid, + const MacAddress &mac, Ip4Address &tor_ip) { + + Agent *agent = peer_manager_->agent(); + + // We dont learn the MAC to IP binding in case of TOR. Populate 0.0.0.0 + // (unknown ip) for the MAC in EVPN route + Ip4Address prefix_ip = Ip4Address::from_string("0.0.0.0"); + int prefix_len = 32; + + VnEntry *vn = agent->vn_table()->Find(vn_uuid); + if (vn == NULL) + return false; + + VrfEntry *vrf = vn->GetVrf(); + if (vrf == NULL) + return false; + + OvsdbRouteData *data = new OvsdbRouteData(this, vn->vxlan_id()->vxlan_id(), + tor_ip, agent->router_id(), + agent->fabric_vrf_name(), + vn->GetName()); + Layer2AgentRouteTable *table = static_cast + (vrf->GetLayer2RouteTable()); + table->AddRemoteVmRouteReq(this, vrf->GetName(), mac, prefix_ip, + vn->vxlan_id()->vxlan_id(), prefix_len, data); + return true; +} + +bool OvsPeer::DeleteOvsRoute(const VnEntry *vn, const MacAddress &mac) { + VrfEntry *vrf = vn->GetVrf(); + if (vrf == NULL) + return false; + + Layer2AgentRouteTable *table = static_cast + (vrf->GetLayer2RouteTable()); + table->DeleteReq(this, vrf->GetName(), mac, vn->vxlan_id()->vxlan_id(), + new OvsdbRouteData(this)); + return true; +} + +const Ip4Address *OvsPeer::NexthopIp(Agent *agent, + const AgentPath *path) const { + const TunnelNH *nh = dynamic_cast(path->nexthop(agent)); + if (nh == NULL) + return agent->router_ip_ptr(); + return nh->GetDip(); +} + +OvsPeerManager::OvsPeerManager(Agent *agent) : gen_id_(0), agent_(agent) { +} + +OvsPeerManager::~OvsPeerManager() { + assert(table_.size() == 0); +} + +OvsPeer *OvsPeerManager::Allocate(const IpAddress &peer_ip) { + OvsPeer *peer = new OvsPeer(peer_ip, gen_id_++, this); + table_.insert(peer); + return peer; +} + +void OvsPeerManager::Free(OvsPeer *peer) { + table_.erase(peer); + delete peer; +} + +Agent *OvsPeerManager::agent() const { + return agent_; +} + +uint32_t OvsPeerManager::Size() const { + return table_.size(); +} diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovs_peer.h b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_route_peer.h similarity index 51% rename from src/vnsw/agent/physical_devices/ovs_tor_agent/ovs_peer.h rename to src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_route_peer.h index aca02eefaf9..427d669312f 100644 --- a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovs_peer.h +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_route_peer.h @@ -1,22 +1,29 @@ /* * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. */ -#ifndef SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVS_PEER_H_ -#define SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVS_PEER_H_ +#ifndef SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVS_PEER_H_ +#define SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVS_PEER_H_ #include #include +class OvsPeerManager; + // Peer for routes added by OVS class OvsPeer : public Peer { public: - OvsPeer(const IpAddress &peer_ip, uint64_t gen_id); + OvsPeer(const IpAddress &peer_ip, uint64_t gen_id, OvsPeerManager *manager); virtual ~OvsPeer(); bool Compare(const Peer *rhs) const; + const Ip4Address *NexthopIp(Agent *agent, const AgentPath *path) const; + bool AddOvsRoute(const boost::uuids::uuid &vn_uuid, const MacAddress &mac, + Ip4Address &tor_ip); + bool DeleteOvsRoute(const VnEntry *vn, const MacAddress &mac); private: IpAddress peer_ip_; uint64_t gen_id_; + OvsPeerManager *peer_manager_; DISALLOW_COPY_AND_ASSIGN(OvsPeer); }; @@ -29,16 +36,19 @@ class OvsPeerManager { }; typedef std::set OvsPeerTable; - OvsPeerManager(); + OvsPeerManager(Agent *agent); virtual ~OvsPeerManager(); OvsPeer *Allocate(const IpAddress &peer_ip); void Free(OvsPeer *peer); + uint32_t Size() const; + Agent *agent() const; private: uint64_t gen_id_; + Agent *agent_; OvsPeerTable table_; DISALLOW_COPY_AND_ASSIGN(OvsPeerManager); }; -#endif // SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVS_PEER_H_ +#endif // SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVS_PEER_H_ diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_wrapper.c b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_wrapper.c new file mode 100644 index 00000000000..ef2ef2fa89f --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_wrapper.c @@ -0,0 +1,570 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +#define OPEN_CONTRAIL_CLIENT +#include +#include +#include +#include +#include + +#include + +void ovsdb_idl_set_callback(struct ovsdb_idl *idl, void *idl_base, + idl_callback cb, txn_ack_callback ack_cb); +struct jsonrpc_msg * ovsdb_idl_encode_monitor_request(struct ovsdb_idl *idl); +void ovsdb_idl_msg_process(struct ovsdb_idl *idl, struct jsonrpc_msg *msg); +struct jsonrpc_msg * ovsdb_idl_txn_encode(struct ovsdb_idl_txn *txn); + +struct ovsdb_idl * +ovsdb_wrapper_idl_create() +{ + vteprec_init(); + return ovsdb_idl_create(NULL, &vteprec_idl_class, true, false); +} + +void +ovsdb_wrapper_idl_destroy(struct ovsdb_idl *idl) +{ + ovsdb_idl_destroy(idl); +} + +const struct vteprec_global * +ovsdb_wrapper_vteprec_global_first(struct ovsdb_idl *idl) +{ + return vteprec_global_first(idl); +} + +int +ovsdb_wrapper_row_type(struct ovsdb_idl_row *row) { + if (row->table->class->columns == vteprec_physical_switch_columns) { + return 0; + } else if (row->table->class->columns == vteprec_logical_switch_columns) { + return 1; + } else if (row->table->class->columns == vteprec_physical_port_columns) { + return 2; + } else if (row->table->class->columns == vteprec_physical_locator_columns) { + return 3; + } else if (row->table->class->columns == vteprec_ucast_macs_local_columns) { + return 4; + } else if (row->table->class->columns == vteprec_ucast_macs_remote_columns) { + return 5; + } else if (row->table->class->columns == vteprec_physical_locator_set_columns) { + return 6; + } else if (row->table->class->columns == vteprec_mcast_macs_local_columns) { + return 7; + } else if (row->table->class->columns == vteprec_mcast_macs_remote_columns) { + return 8; + } + return 100; +} + +bool +ovsdb_wrapper_msg_echo_req(struct jsonrpc_msg *msg) { + return (msg->type == JSONRPC_REQUEST && !strcmp(msg->method, "echo")); +} + +bool +ovsdb_wrapper_msg_echo_reply(struct jsonrpc_msg *msg) { + return (msg->type == JSONRPC_REPLY && msg->id && + msg->id->type == JSON_STRING && !strcmp(msg->id->u.string, "echo")); +} + +struct jsonrpc_msg * +ovsdb_wrapper_jsonrpc_create_reply(struct jsonrpc_msg *msg) { + return jsonrpc_create_reply(json_clone(msg->params), msg->id); +} + +void +ovsdb_wrapper_idl_set_callback(struct ovsdb_idl *idl, void *idl_base, + idl_callback cb, txn_ack_callback ack_cb) +{ + ovsdb_idl_set_callback(idl, idl_base, cb, ack_cb); +} + +struct jsonrpc_msg * +ovsdb_wrapper_idl_encode_monitor_request(struct ovsdb_idl *idl) +{ + return ovsdb_idl_encode_monitor_request(idl); +} + +void +ovsdb_wrapper_idl_msg_process(struct ovsdb_idl *idl, struct jsonrpc_msg *msg) +{ + ovsdb_idl_msg_process(idl, msg); +} + +struct json * +ovsdb_wrapper_jsonrpc_msg_to_json(struct jsonrpc_msg *msg) +{ + return jsonrpc_msg_to_json(msg); +} + +char * +ovsdb_wrapper_json_to_string(const struct json *msg, int flag) +{ + return json_to_string(msg, flag); +} + +void +ovsdb_wrapper_json_destroy(struct json *msg) +{ + json_destroy(msg); +} + +struct json_parser * +ovsdb_wrapper_json_parser_create(int flag) +{ + return json_parser_create(flag); +} + +size_t +ovsdb_wrapper_json_parser_feed(struct json_parser *parser, const char *msg, + size_t len) +{ + return json_parser_feed(parser, msg, len); +} + +bool +ovsdb_wrapper_json_parser_is_done(const struct json_parser *parser) +{ + return json_parser_is_done(parser); +} + +struct json * +ovsdb_wrapper_json_parser_finish(struct json_parser *parser) +{ + return json_parser_finish(parser); +} + +char * +ovsdb_wrapper_jsonrpc_msg_from_json(struct json *msg, struct jsonrpc_msg **rpc) +{ + return jsonrpc_msg_from_json(msg, rpc); +} + +void +ovsdb_wrapper_jsonrpc_msg_destroy(struct jsonrpc_msg *msg) +{ + jsonrpc_msg_destroy(msg); +} + +struct ovsdb_idl_txn * +ovsdb_wrapper_idl_txn_create(struct ovsdb_idl *idl) +{ + return ovsdb_idl_txn_create(idl); +} + +void +ovsdb_wrapper_idl_txn_destroy(struct ovsdb_idl_txn *txn) +{ + ovsdb_idl_txn_destroy(txn); +} + +bool +ovsdb_wrapper_is_txn_success(struct ovsdb_idl_txn *txn) +{ + return ovsdb_idl_is_txn_success(txn); +} + +const char * +ovsdb_wrapper_txn_get_error(struct ovsdb_idl_txn *txn) +{ + return ovsdb_idl_txn_get_error(txn); +} + +struct jsonrpc_msg * +ovsdb_wrapper_idl_txn_encode(struct ovsdb_idl_txn *txn) +{ + return ovsdb_idl_txn_encode(txn); +} + +/* physical switch */ +char * +ovsdb_wrapper_physical_switch_name(struct ovsdb_idl_row *row) +{ + struct vteprec_physical_switch *ps = + row ? CONTAINER_OF(row, struct vteprec_physical_switch, header_) : NULL; + return ps->name; +} + +const char * +ovsdb_wrapper_physical_switch_tunnel_ip(struct ovsdb_idl_row *row) +{ + struct vteprec_physical_switch *ps = + row ? CONTAINER_OF(row, struct vteprec_physical_switch, header_) : NULL; + if (ps->n_tunnel_ips == 0) { + return "0.0.0.0"; + } + /* return the first tunnel ip. */ + return ps->tunnel_ips[0]; +} + +/* logical switch */ +char * +ovsdb_wrapper_logical_switch_name(struct ovsdb_idl_row *row) +{ + struct vteprec_logical_switch *ls = + row ? CONTAINER_OF(row, struct vteprec_logical_switch, header_) : NULL; + return ls->name; +} + +int64_t +ovsdb_wrapper_logical_switch_tunnel_key(struct ovsdb_idl_row *row) +{ + struct vteprec_logical_switch *ls = + row ? CONTAINER_OF(row, struct vteprec_logical_switch, header_) : NULL; + if (ls->n_tunnel_key == 0) { + return 0; + } + return ls->tunnel_key[0]; +} + +struct ovsdb_idl_row * +ovsdb_wrapper_add_logical_switch(struct ovsdb_idl_txn *txn, + struct ovsdb_idl_row *row, const char *name, int64_t vxlan) +{ + struct vteprec_logical_switch *ls = + row ? CONTAINER_OF(row, struct vteprec_logical_switch, header_) : NULL; + if (ls == NULL) + ls = vteprec_logical_switch_insert(txn); + vteprec_logical_switch_set_name(ls, name); + vteprec_logical_switch_set_tunnel_key(ls, &vxlan, 1); + return &(ls->header_); +} + +void +ovsdb_wrapper_delete_logical_switch(struct ovsdb_idl_row *row) +{ + struct vteprec_logical_switch *ls = + CONTAINER_OF(row, struct vteprec_logical_switch, header_); + vteprec_logical_switch_delete(ls); +} + +/* physical port */ +char * +ovsdb_wrapper_physical_port_name(struct ovsdb_idl_row *row) +{ + struct vteprec_physical_port *p = + row ? CONTAINER_OF(row, struct vteprec_physical_port, header_) : NULL; + return p->name; +} + +size_t +ovsdb_wrapper_physical_port_vlan_binding_count(struct ovsdb_idl_row *row) +{ + struct vteprec_physical_port *p = + row ? CONTAINER_OF(row, struct vteprec_physical_port, header_) : NULL; + return p->n_vlan_bindings; +} + +void +ovsdb_wrapper_physical_port_vlan_binding(struct ovsdb_idl_row *row, + struct ovsdb_wrapper_port_vlan_binding *binding) +{ + struct vteprec_physical_port *p = + row ? CONTAINER_OF(row, struct vteprec_physical_port, header_) : NULL; + size_t count = p->n_vlan_bindings; + size_t i = 0; + while (i < count) { + binding[i].vlan = p->key_vlan_bindings[i]; + binding[i].ls = ((struct ovsdb_idl_row *) ((char *)(p->value_vlan_bindings[i]) + offsetof(struct vteprec_logical_switch, header_))); + i++; + } +} + +size_t +ovsdb_wrapper_physical_port_vlan_stats_count(struct ovsdb_idl_row *row) +{ + struct vteprec_physical_port *p = + row ? CONTAINER_OF(row, struct vteprec_physical_port, header_) : NULL; + return p->n_vlan_stats; +} + +void +ovsdb_wrapper_physical_port_vlan_stats(struct ovsdb_idl_row *row, + struct ovsdb_wrapper_port_vlan_stats *stats) +{ + struct vteprec_physical_port *p = + row ? CONTAINER_OF(row, struct vteprec_physical_port, header_) : NULL; + size_t count = p->n_vlan_stats; + size_t i = 0; + while (i < count) { + stats[i].vlan = p->key_vlan_stats[i]; + stats[i].stats = ((struct ovsdb_idl_row *) ((char *)(p->value_vlan_stats[i]) + offsetof(struct vteprec_logical_binding_stats, header_))); + i++; + } +} + +void +ovsdb_wrapper_update_physical_port(struct ovsdb_idl_txn *txn, + struct ovsdb_idl_row *row, + struct ovsdb_wrapper_port_vlan_binding *bindings, size_t binding_count) +{ + struct vteprec_physical_port *p = + CONTAINER_OF(row, struct vteprec_physical_port, header_); + size_t i = 0; + int64_t binding_keys[binding_count]; + struct vteprec_logical_switch *binding_values[binding_count]; + while (i < binding_count) { + binding_keys[i] = bindings[i].vlan; + binding_values[i] = CONTAINER_OF(bindings[i].ls, struct vteprec_logical_switch, header_); + i++; + } + vteprec_physical_port_set_vlan_bindings(p, binding_keys, binding_values, + binding_count); +} + +/* physical locator */ +char * +ovsdb_wrapper_physical_locator_dst_ip(struct ovsdb_idl_row *row) +{ + struct vteprec_physical_locator *p = + row ? CONTAINER_OF(row, struct vteprec_physical_locator, header_) : NULL; + return p->dst_ip; +} + +void +ovsdb_wrapper_add_physical_locator(struct ovsdb_idl_txn *txn, + struct ovsdb_idl_row *row, const char *dip) +{ + struct vteprec_physical_locator *p = + row ? CONTAINER_OF(row, struct vteprec_physical_locator, header_) : NULL; + if (p == NULL) + p = vteprec_physical_locator_insert(txn); + vteprec_physical_locator_set_dst_ip(p, dip); + vteprec_physical_locator_set_encapsulation_type(p, "vxlan_over_ipv4"); +} + +void +ovsdb_wrapper_delete_physical_locator(struct ovsdb_idl_row *row) +{ + struct vteprec_physical_locator *p = + row ? CONTAINER_OF(row, struct vteprec_physical_locator, header_) : NULL; + vteprec_physical_locator_delete(p); +} + +/* unicast mac local */ +char * +ovsdb_wrapper_ucast_mac_local_mac(struct ovsdb_idl_row *row) +{ + struct vteprec_ucast_macs_local *mac = + row ? CONTAINER_OF(row, struct vteprec_ucast_macs_local, header_) : NULL; + return mac->MAC; +} + +char * +ovsdb_wrapper_ucast_mac_local_ip(struct ovsdb_idl_row *row) +{ + struct vteprec_ucast_macs_local *mac = + row ? CONTAINER_OF(row, struct vteprec_ucast_macs_local, header_) : NULL; + return mac->ipaddr; +} + +char * +ovsdb_wrapper_ucast_mac_local_logical_switch(struct ovsdb_idl_row *row) +{ + struct vteprec_ucast_macs_local *mac = + row ? CONTAINER_OF(row, struct vteprec_ucast_macs_local, header_) : NULL; + if (mac->logical_switch) { + return mac->logical_switch->name; + } + return NULL; +} + +char * +ovsdb_wrapper_ucast_mac_local_dst_ip(struct ovsdb_idl_row *row) +{ + struct vteprec_ucast_macs_local *mac = + row ? CONTAINER_OF(row, struct vteprec_ucast_macs_local, header_) : NULL; + if (mac->locator) { + return mac->locator->dst_ip; + } + return NULL; +} + +/* unicast mac remote */ +void +obvsdb_wrapper_add_ucast_mac_remote(struct ovsdb_idl_txn *txn, const char *mac, + struct ovsdb_idl_row *ls, struct ovsdb_idl_row *pl, const char *dest_ip) +{ + struct vteprec_ucast_macs_remote *ucast = + vteprec_ucast_macs_remote_insert(txn); + vteprec_ucast_macs_remote_set_MAC(ucast, mac); + struct vteprec_logical_switch *l_switch = + ls? CONTAINER_OF(ls, struct vteprec_logical_switch, header_) : NULL; + vteprec_ucast_macs_remote_set_logical_switch(ucast, l_switch); + struct vteprec_physical_locator *p = + pl ? CONTAINER_OF(pl, struct vteprec_physical_locator, header_) : NULL; + if (p == NULL) { + p = vteprec_physical_locator_insert(txn); + vteprec_physical_locator_set_dst_ip(p, dest_ip); + vteprec_physical_locator_set_encapsulation_type(p, "vxlan_over_ipv4"); + } + vteprec_ucast_macs_remote_set_locator(ucast, p); +} + +void +ovsdb_wrapper_delete_ucast_mac_remote(struct ovsdb_idl_row *row) +{ + struct vteprec_ucast_macs_remote *ucast = + row ? CONTAINER_OF(row, struct vteprec_ucast_macs_remote, header_) : NULL; + vteprec_ucast_macs_remote_delete(ucast); +} + +char * +ovsdb_wrapper_ucast_mac_remote_mac(struct ovsdb_idl_row *row) +{ + struct vteprec_ucast_macs_remote *mac = + row ? CONTAINER_OF(row, struct vteprec_ucast_macs_remote, header_) : NULL; + return mac->MAC; +} + +char * +ovsdb_wrapper_ucast_mac_remote_ip(struct ovsdb_idl_row *row) +{ + struct vteprec_ucast_macs_remote *mac = + row ? CONTAINER_OF(row, struct vteprec_ucast_macs_remote, header_) : NULL; + return mac->ipaddr; +} + +char * +ovsdb_wrapper_ucast_mac_remote_logical_switch(struct ovsdb_idl_row *row) +{ + struct vteprec_ucast_macs_remote *mac = + row ? CONTAINER_OF(row, struct vteprec_ucast_macs_remote, header_) : NULL; + if (mac->logical_switch) { + return mac->logical_switch->name; + } + return NULL; +} + +char * +ovsdb_wrapper_ucast_mac_remote_dst_ip(struct ovsdb_idl_row *row) +{ + struct vteprec_ucast_macs_remote *mac = + row ? CONTAINER_OF(row, struct vteprec_ucast_macs_remote, header_) : NULL; + if (mac->locator) { + return mac->locator->dst_ip; + } + return NULL; +} + +/* multicast mac local */ +void +ovsdb_wrapper_delete_mcast_mac_local(struct ovsdb_idl_row *row) +{ + struct vteprec_mcast_macs_local *mcast = + row ? CONTAINER_OF(row, struct vteprec_mcast_macs_local, header_) : NULL; + struct vteprec_physical_locator_set *l_set = mcast->locator_set; + vteprec_physical_locator_set_delete(l_set); + vteprec_mcast_macs_local_delete(mcast); +} + +char * +ovsdb_wrapper_mcast_mac_local_mac(struct ovsdb_idl_row *row) +{ + struct vteprec_mcast_macs_local *mcast = + row ? CONTAINER_OF(row, struct vteprec_mcast_macs_local, header_) : NULL; + return mcast->MAC; +} + +char * +ovsdb_wrapper_mcast_mac_local_logical_switch(struct ovsdb_idl_row *row) +{ + struct vteprec_mcast_macs_local *mcast = + row ? CONTAINER_OF(row, struct vteprec_mcast_macs_local, header_) : NULL; + if (mcast->logical_switch) + return mcast->logical_switch->name; + return NULL; +} + +struct ovsdb_idl_row * +ovsdb_wrapper_mcast_mac_local_physical_locator_set(struct ovsdb_idl_row *row) +{ + struct vteprec_mcast_macs_local *mcast = + row ? CONTAINER_OF(row, struct vteprec_mcast_macs_local, header_) : NULL; + return &(mcast->locator_set->header_); +} + +/* multicast mac remote */ +void +ovsdb_wrapper_add_mcast_mac_remote(struct ovsdb_idl_txn *txn, + struct ovsdb_idl_row *row, const char *mac, struct ovsdb_idl_row *ls, + struct ovsdb_idl_row *pl, const char *dst_ip) +{ + struct vteprec_mcast_macs_remote *mcast = + row ? CONTAINER_OF(row, struct vteprec_mcast_macs_remote, header_) : NULL; + struct vteprec_physical_locator_set *l_set = + vteprec_physical_locator_set_insert(txn); + if (mcast == NULL) { + mcast = vteprec_mcast_macs_remote_insert(txn); + } + vteprec_mcast_macs_remote_set_MAC(mcast, mac); + vteprec_mcast_macs_remote_set_locator_set(mcast, l_set); + struct vteprec_logical_switch *l_switch = + ls ? CONTAINER_OF(ls, struct vteprec_logical_switch, header_) : NULL; + vteprec_mcast_macs_remote_set_logical_switch(mcast, l_switch); + struct vteprec_physical_locator *p = + pl ? CONTAINER_OF(pl, struct vteprec_physical_locator, header_) : NULL; + if (p == NULL) { + p = vteprec_physical_locator_insert(txn); + vteprec_physical_locator_set_dst_ip(p, dst_ip); + vteprec_physical_locator_set_encapsulation_type(p, "vxlan_over_ipv4"); + } + vteprec_physical_locator_set_set_locators(l_set, &p, 1); +} + +void +ovsdb_wrapper_delete_mcast_mac_remote(struct ovsdb_idl_row *row) +{ + struct vteprec_mcast_macs_remote *mcast = + row ? CONTAINER_OF(row, struct vteprec_mcast_macs_remote, header_) : NULL; + struct vteprec_physical_locator_set *l_set = mcast->locator_set; + vteprec_physical_locator_set_delete(l_set); + vteprec_mcast_macs_remote_delete(mcast); +} + +char * +ovsdb_wrapper_mcast_mac_remote_mac(struct ovsdb_idl_row *row) +{ + struct vteprec_mcast_macs_remote *mcast = + row ? CONTAINER_OF(row, struct vteprec_mcast_macs_remote, header_) : NULL; + return mcast->MAC; +} + +char * +ovsdb_wrapper_mcast_mac_remote_logical_switch(struct ovsdb_idl_row *row) +{ + struct vteprec_mcast_macs_remote *mcast = + row ? CONTAINER_OF(row, struct vteprec_mcast_macs_remote, header_) : NULL; + if (mcast->logical_switch) + return mcast->logical_switch->name; + return NULL; +} + +struct ovsdb_idl_row * +ovsdb_wrapper_mcast_mac_remote_physical_locator_set(struct ovsdb_idl_row *row) +{ + struct vteprec_mcast_macs_remote *mcast = + row ? CONTAINER_OF(row, struct vteprec_mcast_macs_remote, header_) : NULL; + return &(mcast->locator_set->header_); +} + +/* logical binding stats */ +void +ovsdb_wrapper_get_logical_binding_stats(struct ovsdb_idl_row *row, + int64_t *in_pkts, int64_t *in_bytes, + int64_t *out_pkts, int64_t *out_bytes) +{ + struct vteprec_logical_binding_stats *stats = + row ? CONTAINER_OF(row, struct vteprec_logical_binding_stats, header_) : NULL; + if (row == NULL) + return; + *in_pkts = stats->packets_from_local; + *in_bytes = stats->bytes_from_local; + *out_pkts = stats->packets_to_local; + *out_bytes = stats->bytes_to_local; +} + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_wrapper.h b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_wrapper.h new file mode 100644 index 00000000000..cb88936a5ee --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_wrapper.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +#ifndef SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVSDB_WRAPPER_H_ +#define SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVSDB_WRAPPER_H_ + +#include + +struct ovsdb_wrapper_port_vlan_binding { + int64_t vlan; + struct ovsdb_idl_row *ls; +}; + +struct ovsdb_wrapper_port_vlan_stats { + int64_t vlan; + struct ovsdb_idl_row *stats; +}; + +/* Wrapper for C APIs */ +struct ovsdb_idl * ovsdb_wrapper_idl_create(); +void ovsdb_wrapper_idl_destroy(struct ovsdb_idl *idl); +const struct vteprec_global *ovsdb_wrapper_vteprec_global_first(struct ovsdb_idl *); +int ovsdb_wrapper_row_type(struct ovsdb_idl_row *row); +bool ovsdb_wrapper_msg_echo_req(struct jsonrpc_msg *msg); +bool ovsdb_wrapper_msg_echo_reply(struct jsonrpc_msg *msg); +struct jsonrpc_msg* ovsdb_wrapper_jsonrpc_create_reply(struct jsonrpc_msg *msg); + +void ovsdb_wrapper_idl_set_callback(struct ovsdb_idl *idl, void *idl_base, + void (*cb)(void*, int, struct ovsdb_idl_row *), + void (*ack_cb)(void*, struct ovsdb_idl_txn *)); +struct jsonrpc_msg *ovsdb_wrapper_idl_encode_monitor_request(struct ovsdb_idl *); +void ovsdb_wrapper_idl_msg_process(struct ovsdb_idl *, struct jsonrpc_msg *msg); +struct json *ovsdb_wrapper_jsonrpc_msg_to_json(struct jsonrpc_msg *); +char *ovsdb_wrapper_json_to_string(const struct json *, int); +void ovsdb_wrapper_json_destroy(struct json *); +struct json_parser *ovsdb_wrapper_json_parser_create(int); +size_t ovsdb_wrapper_json_parser_feed(struct json_parser *, const char *, size_t); +bool ovsdb_wrapper_json_parser_is_done(const struct json_parser *); +struct json *ovsdb_wrapper_json_parser_finish(struct json_parser *); +char *ovsdb_wrapper_jsonrpc_msg_from_json(struct json *, struct jsonrpc_msg **); +void ovsdb_wrapper_jsonrpc_msg_destroy(struct jsonrpc_msg *msg); + +struct ovsdb_idl_txn *ovsdb_wrapper_idl_txn_create(struct ovsdb_idl *idl); +void ovsdb_wrapper_idl_txn_destroy(struct ovsdb_idl_txn *txn); +bool ovsdb_wrapper_is_txn_success(struct ovsdb_idl_txn *txn); +const char *ovsdb_wrapper_txn_get_error(struct ovsdb_idl_txn *txn); +struct jsonrpc_msg *ovsdb_wrapper_idl_txn_encode(struct ovsdb_idl_txn *txn); + +/* Physical Switch */ +char *ovsdb_wrapper_physical_switch_name(struct ovsdb_idl_row *row); +const char *ovsdb_wrapper_physical_switch_tunnel_ip(struct ovsdb_idl_row *row); + +/* Logical Switch */ +char *ovsdb_wrapper_logical_switch_name(struct ovsdb_idl_row *row); +int64_t ovsdb_wrapper_logical_switch_tunnel_key(struct ovsdb_idl_row *row); +struct ovsdb_idl_row *ovsdb_wrapper_add_logical_switch(struct ovsdb_idl_txn *, + struct ovsdb_idl_row *, const char *, int64_t); +void ovsdb_wrapper_delete_logical_switch(struct ovsdb_idl_row *); + +/* Physical Port */ +char *ovsdb_wrapper_physical_port_name(struct ovsdb_idl_row *row); +size_t ovsdb_wrapper_physical_port_vlan_binding_count(struct ovsdb_idl_row *row); +void ovsdb_wrapper_physical_port_vlan_binding(struct ovsdb_idl_row *row, + struct ovsdb_wrapper_port_vlan_binding*); +size_t ovsdb_wrapper_physical_port_vlan_stats_count(struct ovsdb_idl_row *row); +void ovsdb_wrapper_physical_port_vlan_stats(struct ovsdb_idl_row *row, + struct ovsdb_wrapper_port_vlan_stats*); +void ovsdb_wrapper_update_physical_port(struct ovsdb_idl_txn *, struct ovsdb_idl_row *, + struct ovsdb_wrapper_port_vlan_binding*, size_t binding_count); + +/* Physical Locator */ +char *ovsdb_wrapper_physical_locator_dst_ip(struct ovsdb_idl_row *row); +void ovsdb_wrapper_add_physical_locator(struct ovsdb_idl_txn *, + struct ovsdb_idl_row *, const char *); +void ovsdb_wrapper_delete_physical_locator(struct ovsdb_idl_row *); + +/* unicast mac local */ +char *ovsdb_wrapper_ucast_mac_local_mac(struct ovsdb_idl_row *row); +char *ovsdb_wrapper_ucast_mac_local_ip(struct ovsdb_idl_row *row); +char *ovsdb_wrapper_ucast_mac_local_logical_switch(struct ovsdb_idl_row *row); +char *ovsdb_wrapper_ucast_mac_local_dst_ip(struct ovsdb_idl_row *row); + +/* unicast mac remote */ +void obvsdb_wrapper_add_ucast_mac_remote(struct ovsdb_idl_txn *txn, + const char *mac, struct ovsdb_idl_row *ls, struct ovsdb_idl_row *pl, + const char *dest_ip); +void ovsdb_wrapper_delete_ucast_mac_remote(struct ovsdb_idl_row *row); +char *ovsdb_wrapper_ucast_mac_remote_mac(struct ovsdb_idl_row *row); +char *ovsdb_wrapper_ucast_mac_remote_ip(struct ovsdb_idl_row *row); +char *ovsdb_wrapper_ucast_mac_remote_logical_switch(struct ovsdb_idl_row *row); +char *ovsdb_wrapper_ucast_mac_remote_dst_ip(struct ovsdb_idl_row *row); + +/* multicast mac local */ +void ovsdb_wrapper_delete_mcast_mac_local(struct ovsdb_idl_row *row); +char *ovsdb_wrapper_mcast_mac_local_mac(struct ovsdb_idl_row *row); +char * +ovsdb_wrapper_mcast_mac_local_logical_switch(struct ovsdb_idl_row *row); +struct ovsdb_idl_row * +ovsdb_wrapper_mcast_mac_local_physical_locator_set(struct ovsdb_idl_row *row); + +/* multicast mac remote */ +void ovsdb_wrapper_add_mcast_mac_remote(struct ovsdb_idl_txn *txn, + struct ovsdb_idl_row *row, const char *mac, struct ovsdb_idl_row *ls, + struct ovsdb_idl_row *pl, const char *dst_ip); +void ovsdb_wrapper_delete_mcast_mac_remote(struct ovsdb_idl_row *row); +char *ovsdb_wrapper_mcast_mac_remote_mac(struct ovsdb_idl_row *row); +char * +ovsdb_wrapper_mcast_mac_remote_logical_switch(struct ovsdb_idl_row *row); +struct ovsdb_idl_row * +ovsdb_wrapper_mcast_mac_remote_physical_locator_set(struct ovsdb_idl_row *row); + +/* logical binding stats */ +void ovsdb_wrapper_get_logical_binding_stats(struct ovsdb_idl_row *row, + int64_t *in_pkts, int64_t *in_bytes, + int64_t *out_pkts, int64_t *out_bytes); + +#endif //SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVSDB_WRAPPER_H_ + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/physical_locator_ovsdb.cc b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/physical_locator_ovsdb.cc new file mode 100644 index 00000000000..70ae6522dfc --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/physical_locator_ovsdb.cc @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +extern "C" { +#include +}; + +#include +#include +#include + +using OVSDB::PhysicalLocatorTable; +using OVSDB::PhysicalLocatorEntry; + +PhysicalLocatorEntry::PhysicalLocatorEntry(PhysicalLocatorTable *table, + const std::string &dip_str) : OvsdbEntry(table), dip_(dip_str) { +} + +PhysicalLocatorEntry::~PhysicalLocatorEntry() { +} + +bool PhysicalLocatorEntry::IsLess(const KSyncEntry &entry) const { + const PhysicalLocatorEntry &pl_entry = + static_cast(entry); + return (dip_ < pl_entry.dip_); +} + +KSyncEntry *PhysicalLocatorEntry::UnresolvedReference() { + return NULL; +} + +PhysicalLocatorTable::PhysicalLocatorTable(OvsdbClientIdl *idl) : + OvsdbObject(idl) { + idl->Register(OvsdbClientIdl::OVSDB_PHYSICAL_LOCATOR, + boost::bind(&PhysicalLocatorTable::OvsdbNotify, this, _1, _2)); +} + +PhysicalLocatorTable::~PhysicalLocatorTable() { + client_idl_->UnRegister(OvsdbClientIdl::OVSDB_PHYSICAL_LOCATOR); +} + +void PhysicalLocatorTable::OvsdbNotify(OvsdbClientIdl::Op op, + struct ovsdb_idl_row *row) { + const char *dip_str = ovsdb_wrapper_physical_locator_dst_ip(row); + PhysicalLocatorEntry key(this, dip_str); + PhysicalLocatorEntry *entry = + static_cast(FindActiveEntry(&key)); + if (op == OvsdbClientIdl::OVSDB_DEL) { + if (entry != NULL) { + OVSDB_TRACE(Trace, "Delete received for Physical Locator " + + entry->dip_); + Delete(entry); + } + } else if (op == OvsdbClientIdl::OVSDB_ADD) { + if (entry == NULL) { + entry = static_cast(Create(&key)); + entry->ovs_entry_ = row; + OVSDB_TRACE(Trace, "Add received for Physical Locator " + + entry->dip_); + } + } else { + assert(0); + } +} + +KSyncEntry *PhysicalLocatorTable::Alloc(const KSyncEntry *key, uint32_t index) { + const PhysicalLocatorEntry *k_entry = + static_cast(key); + PhysicalLocatorEntry *entry = new PhysicalLocatorEntry(this, k_entry->dip_); + return entry; +} + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/physical_locator_ovsdb.h b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/physical_locator_ovsdb.h new file mode 100644 index 00000000000..6370c087182 --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/physical_locator_ovsdb.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +#ifndef SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_PHYSICAL_LOCATOR_OVSDB_H_ +#define SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_PHYSICAL_LOCATOR_OVSDB_H_ + +#include +#include + +namespace OVSDB { +class PhysicalLocatorTable : public OvsdbObject { +public: + PhysicalLocatorTable(OvsdbClientIdl *idl); + virtual ~PhysicalLocatorTable(); + + void OvsdbNotify(OvsdbClientIdl::Op, struct ovsdb_idl_row *); + KSyncEntry *Alloc(const KSyncEntry *key, uint32_t index); + +private: + DISALLOW_COPY_AND_ASSIGN(PhysicalLocatorTable); +}; + +class PhysicalLocatorEntry : public OvsdbEntry { +public: + PhysicalLocatorEntry(PhysicalLocatorTable *table, + const std::string &dip_str); + virtual ~PhysicalLocatorEntry(); + + bool IsLess(const KSyncEntry&) const; + std::string ToString() const {return "Physical Locator";} + KSyncEntry* UnresolvedReference(); +private: + + friend class PhysicalLocatorTable; + std::string dip_; + DISALLOW_COPY_AND_ASSIGN(PhysicalLocatorEntry); +}; +}; // namespace OVSDB + +#endif // SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_PHYSICAL_LOCATOR_OVSDB_H_ + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/physical_port_ovsdb.cc b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/physical_port_ovsdb.cc new file mode 100644 index 00000000000..2a37dea868d --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/physical_port_ovsdb.cc @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +extern "C" { +#include +}; + +#include + +#include +#include +#include +#include + +#include +#include +#include + +using OVSDB::OvsdbClient; +using OVSDB::OvsdbClientSession; +using OVSDB::PhysicalPortEntry; +using OVSDB::PhysicalPortTable; + +PhysicalPortEntry::PhysicalPortEntry(PhysicalPortTable *table, + const char *name) : OvsdbEntry(table), name_(name), binding_table_(), + ovs_binding_table_() { +} + +PhysicalPortEntry::PhysicalPortEntry(PhysicalPortTable *table, + const std::string &name) : OvsdbEntry(table), name_(name), + binding_table_(), ovs_binding_table_() { +} + +PhysicalPortEntry::~PhysicalPortEntry() { +} + +bool PhysicalPortEntry::IsLess(const KSyncEntry &entry) const { + const PhysicalPortEntry &ps_entry = + static_cast(entry); + return (name_.compare(ps_entry.name_) < 0); +} + +KSyncEntry *PhysicalPortEntry::UnresolvedReference() { + return NULL; +} + +void PhysicalPortEntry::Encode(struct ovsdb_idl_txn *txn) { + if (GetState() == KSyncEntry::TEMP || IsDeleted()) { + /* + * we can only modify the vlan bindings in physical port + * table as we don't own the table, we are not suppose to create + * a new port entry in the table, so return from here if entry is + * marked temporary or deleted. + */ + return; + } + struct ovsdb_wrapper_port_vlan_binding binding[binding_table_.size()]; + VlanLSTable::iterator it = binding_table_.begin(); + std::size_t i = 0; + for ( ; it != binding_table_.end(); it++) { + struct ovsdb_idl_row *ls = it->second->ovs_entry(); + if (ls != NULL) { + binding[i].ls = ls; + binding[i].vlan = it->first; + i++; + } + } + ovsdb_wrapper_update_physical_port(txn, ovs_entry_, binding, i); +} + +void PhysicalPortEntry::AddBinding(int16_t vlan, LogicalSwitchEntry *ls) { + binding_table_[vlan] = ls; +} + +void PhysicalPortEntry::DeleteBinding(int16_t vlan, LogicalSwitchEntry *ls) { + binding_table_.erase(vlan); +} + +const std::string &PhysicalPortEntry::name() const { + return name_; +} + +const PhysicalPortEntry::VlanLSTable & +PhysicalPortEntry::ovs_binding_table() const { + return ovs_binding_table_; +} + +const PhysicalPortEntry::VlanStatsTable & +PhysicalPortEntry::stats_table() const { + return stats_table_; +} + +void PhysicalPortEntry::OverrideOvs() { + struct ovsdb_idl_txn *txn = table_->client_idl()->CreateTxn(this); + Encode(txn); + struct jsonrpc_msg *msg = ovsdb_wrapper_idl_txn_encode(txn); + if (msg == NULL) { + table_->client_idl()->DeleteTxn(txn); + return; + } + table_->client_idl()->SendJsonRpc(msg); +} + +PhysicalPortTable::PhysicalPortTable(OvsdbClientIdl *idl) : + OvsdbObject(idl) { + idl->Register(OvsdbClientIdl::OVSDB_PHYSICAL_PORT, + boost::bind(&PhysicalPortTable::Notify, this, _1, _2)); +} + +PhysicalPortTable::~PhysicalPortTable() { + client_idl_->UnRegister(OvsdbClientIdl::OVSDB_PHYSICAL_PORT); +} + +void PhysicalPortTable::Notify(OvsdbClientIdl::Op op, + struct ovsdb_idl_row *row) { + bool override_ovs = false; + PhysicalPortEntry key(this, ovsdb_wrapper_physical_port_name(row)); + PhysicalPortEntry *entry = static_cast(FindActiveEntry(&key)); + if (op == OvsdbClientIdl::OVSDB_DEL) { + OVSDB_TRACE(Trace, "Delete of Physical Port " + + std::string(ovsdb_wrapper_physical_port_name(row))); + if (entry != NULL) { + Delete(entry); + } + } else if (op == OvsdbClientIdl::OVSDB_ADD) { + if (entry == NULL) { + OVSDB_TRACE(Trace, "Add/Change of Physical Port " + + std::string(ovsdb_wrapper_physical_port_name(row))); + entry = static_cast(Create(&key)); + entry->ovs_entry_ = row; + } + PhysicalPortEntry::VlanLSTable old(entry->ovs_binding_table_); + std::size_t count = ovsdb_wrapper_physical_port_vlan_binding_count(row); + struct ovsdb_wrapper_port_vlan_binding new_bind[count]; + ovsdb_wrapper_physical_port_vlan_binding(row, new_bind); + for (std::size_t i = 0; i < count; i++) { + if (entry->binding_table_.find(new_bind[i].vlan) == + entry->binding_table_.end()) { + /* + * Entries present which are not owned by us, + * write port transaction to override the value. + */ + override_ovs = true; + continue; + } + LogicalSwitchEntry key(client_idl_->logical_switch_table(), + ovsdb_wrapper_logical_switch_name(new_bind[i].ls)); + LogicalSwitchEntry *ls_entry = + static_cast( + client_idl_->logical_switch_table()->Find(&key)); + entry->ovs_binding_table_[new_bind[i].vlan] = ls_entry; + old.erase(new_bind[i].vlan); + } + count = ovsdb_wrapper_physical_port_vlan_stats_count(row); + struct ovsdb_wrapper_port_vlan_stats stats[count]; + ovsdb_wrapper_physical_port_vlan_stats(row, stats); + entry->stats_table_.clear(); + for (std::size_t i = 0; i < count; i++) { + entry->stats_table_[stats[i].vlan] = stats[i].stats; + } + PhysicalPortEntry::VlanLSTable::iterator it = old.begin(); + for ( ; it != old.end(); it++) { + if (entry->binding_table_.find(it->first) != + entry->binding_table_.end()) { + /* + * Entry owned by us is somehow deleted, + * write port transaction to override the value. + */ + override_ovs = true; + } + entry->ovs_binding_table_.erase(it->first); + } + } else { + assert(0); + } + if (override_ovs) + entry->OverrideOvs(); +} + +KSyncEntry *PhysicalPortTable::Alloc(const KSyncEntry *key, uint32_t index) { + const PhysicalPortEntry *k_entry = + static_cast(key); + PhysicalPortEntry *entry = new PhysicalPortEntry(this, k_entry->name_); + return entry; +} + +///////////////////////////////////////////////////////////////////////////// +// Sandesh routines +///////////////////////////////////////////////////////////////////////////// +class PhysicalPortSandeshTask : public Task { +public: + PhysicalPortSandeshTask(std::string resp_ctx) : + Task((TaskScheduler::GetInstance()->GetTaskId("Agent::KSync")), -1), + resp_(new OvsdbPhysicalPortResp()), resp_data_(resp_ctx) { + } + virtual ~PhysicalPortSandeshTask() {} + virtual bool Run() { + std::vector port_list; + TorAgentInit *init = + static_cast(Agent::GetInstance()->agent_init()); + OvsdbClientSession *session = init->ovsdb_client()->next_session(NULL); + PhysicalPortTable *table = + session->client_idl()->physical_port_table(); + PhysicalPortEntry *entry = + static_cast(table->Next(NULL)); + while (entry != NULL) { + OvsdbPhysicalPortEntry pentry; + pentry.set_state(entry->StateString()); + pentry.set_name(entry->name()); + const PhysicalPortEntry::VlanLSTable &bindings = + entry->ovs_binding_table(); + const PhysicalPortEntry::VlanStatsTable &stats_table = + entry->stats_table(); + PhysicalPortEntry::VlanLSTable::const_iterator it = + bindings.begin(); + std::vector vlan_list; + for (; it != bindings.end(); it++) { + OvsdbPhysicalPortVlanInfo vlan; + vlan.set_vlan(it->first); + vlan.set_logical_switch(it->second->name()); + PhysicalPortEntry::VlanStatsTable::const_iterator stats_it = + stats_table.find(it->first); + if (stats_it != stats_table.end()) { + int64_t in_pkts, in_bytes, out_pkts, out_bytes; + ovsdb_wrapper_get_logical_binding_stats(stats_it->second, + &in_pkts, &in_bytes, &out_pkts, &out_bytes); + vlan.set_in_pkts(in_pkts); + vlan.set_in_bytes(in_bytes); + vlan.set_out_pkts(out_pkts); + vlan.set_out_bytes(out_bytes); + } else { + vlan.set_in_pkts(0); + vlan.set_in_bytes(0); + vlan.set_out_pkts(0); + vlan.set_out_bytes(0); + } + vlan_list.push_back(vlan); + } + pentry.set_vlans(vlan_list); + port_list.push_back(pentry); + entry = static_cast(table->Next(entry)); + } + resp_->set_port(port_list); + SendResponse(); + return true; + } +private: + void SendResponse() { + resp_->set_context(resp_data_); + resp_->set_more(false); + resp_->Response(); + } + + OvsdbPhysicalPortResp *resp_; + std::string resp_data_; + DISALLOW_COPY_AND_ASSIGN(PhysicalPortSandeshTask); +}; + +void OvsdbPhysicalPortReq::HandleRequest() const { + PhysicalPortSandeshTask *task = new PhysicalPortSandeshTask(context()); + TaskScheduler *scheduler = TaskScheduler::GetInstance(); + scheduler->Enqueue(task); +} + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/physical_port_ovsdb.h b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/physical_port_ovsdb.h new file mode 100644 index 00000000000..2f2cfb20cf5 --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/physical_port_ovsdb.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +#ifndef SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_PHYSICAL_PORT_OVSDB_H_ +#define SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_PHYSICAL_PORT_OVSDB_H_ + +#include +#include + +namespace OVSDB { +class PhysicalPortTable : public OvsdbObject { +public: + PhysicalPortTable(OvsdbClientIdl *idl); + virtual ~PhysicalPortTable(); + + void Notify(OvsdbClientIdl::Op, struct ovsdb_idl_row *); + KSyncEntry *Alloc(const KSyncEntry *key, uint32_t index); +private: + DISALLOW_COPY_AND_ASSIGN(PhysicalPortTable); +}; + +class PhysicalPortEntry : public OvsdbEntry { +public: + typedef std::map VlanLSTable; + typedef std::map VlanStatsTable; + PhysicalPortEntry(PhysicalPortTable *table, const char *name); + PhysicalPortEntry(PhysicalPortTable *table, const std::string &name); + ~PhysicalPortEntry(); + + bool IsLess(const KSyncEntry&) const; + std::string ToString() const {return "Physical Port";} + KSyncEntry* UnresolvedReference(); + void Encode(struct ovsdb_idl_txn *); + void AddBinding(int16_t vlan, LogicalSwitchEntry *ls); + void DeleteBinding(int16_t vlan, LogicalSwitchEntry *ls); + + const std::string &name() const; + const VlanLSTable &ovs_binding_table() const; + const VlanStatsTable &stats_table() const; + +private: + friend class PhysicalPortTable; + void OverrideOvs(); + std::string name_; + struct ovsdb_idl_row *ovs_entry_; + VlanLSTable binding_table_; + VlanLSTable ovs_binding_table_; + VlanStatsTable stats_table_; + DISALLOW_COPY_AND_ASSIGN(PhysicalPortEntry); +}; +}; + +#endif //SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_PHYSICAL_PORT_OVSDB_H_ + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/physical_switch_ovsdb.cc b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/physical_switch_ovsdb.cc new file mode 100644 index 00000000000..788e261d372 --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/physical_switch_ovsdb.cc @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +extern "C" { +#include +}; + +#include + +#include +#include +#include +#include +#include +#include + +using OVSDB::OvsdbClient; +using OVSDB::OvsdbClientSession; +using OVSDB::PhysicalSwitchEntry; +using OVSDB::PhysicalSwitchTable; + +PhysicalSwitchEntry::PhysicalSwitchEntry(PhysicalSwitchTable *table, + const std::string &name) : OvsdbEntry(table), name_(name), + tunnel_ip_() { +} + +PhysicalSwitchEntry::~PhysicalSwitchEntry() { +} + +Ip4Address &PhysicalSwitchEntry::tunnel_ip() { + return tunnel_ip_; +} + +const std::string &PhysicalSwitchEntry::name() { + return name_; +} + +void PhysicalSwitchEntry::set_tunnel_ip(std::string ip) { + boost::system::error_code ec; + tunnel_ip_ = Ip4Address::from_string(ip, ec); +} + +bool PhysicalSwitchEntry::IsLess(const KSyncEntry &entry) const { + const PhysicalSwitchEntry &ps_entry = + static_cast(entry); + return (name_ < ps_entry.name_); +} + +KSyncEntry *PhysicalSwitchEntry::UnresolvedReference() { + return NULL; +} + +void PhysicalSwitchEntry::SendTrace(Trace event) const { + SandeshPhysicalSwitchInfo info; + if (event == ADD) { + info.set_op("Add"); + } else { + info.set_op("Delete"); + } + info.set_name(name_); + OVSDB_TRACE(PhysicalSwitch, info); +} + +PhysicalSwitchTable::PhysicalSwitchTable(OvsdbClientIdl *idl) : + OvsdbObject(idl) { + idl->Register(OvsdbClientIdl::OVSDB_PHYSICAL_SWITCH, + boost::bind(&PhysicalSwitchTable::Notify, this, _1, _2)); +} + +PhysicalSwitchTable::~PhysicalSwitchTable() { + client_idl_->UnRegister(OvsdbClientIdl::OVSDB_PHYSICAL_SWITCH); +} + +void PhysicalSwitchTable::Notify(OvsdbClientIdl::Op op, + struct ovsdb_idl_row *row) { + PhysicalSwitchEntry key(this, ovsdb_wrapper_physical_switch_name(row)); + PhysicalSwitchEntry *entry = + static_cast(FindActiveEntry(&key)); + if (op == OvsdbClientIdl::OVSDB_DEL) { + if (entry != NULL) { + entry->SendTrace(PhysicalSwitchEntry::DEL); + Delete(entry); + } + } else if (op == OvsdbClientIdl::OVSDB_ADD) { + if (entry == NULL) { + entry = static_cast(Create(&key)); + entry->SendTrace(PhysicalSwitchEntry::ADD); + } + entry->set_tunnel_ip(ovsdb_wrapper_physical_switch_tunnel_ip(row)); + } else { + assert(0); + } +} + +KSyncEntry *PhysicalSwitchTable::Alloc(const KSyncEntry *key, uint32_t index) { + const PhysicalSwitchEntry *k_entry = + static_cast(key); + PhysicalSwitchEntry *entry = new PhysicalSwitchEntry(this, k_entry->name_); + return entry; +} + + +///////////////////////////////////////////////////////////////////////////// +// Sandesh routines +///////////////////////////////////////////////////////////////////////////// +class PhysicalSwitchSandeshTask : public Task { +public: + PhysicalSwitchSandeshTask(std::string resp_ctx) : + Task((TaskScheduler::GetInstance()->GetTaskId("Agent::KSync")), -1), + resp_(new OvsdbPhysicalSwitchResp()), resp_data_(resp_ctx) { + } + virtual ~PhysicalSwitchSandeshTask() {} + virtual bool Run() { + std::vector pswitch; + TorAgentInit *init = + static_cast(Agent::GetInstance()->agent_init()); + OvsdbClientSession *session = init->ovsdb_client()->next_session(NULL); + PhysicalSwitchTable *table = + session->client_idl()->physical_switch_table(); + PhysicalSwitchEntry *entry = + static_cast(table->Next(NULL)); + while (entry != NULL) { + OvsdbPhysicalSwitchEntry pentry; + pentry.set_state(entry->StateString()); + pentry.set_name(entry->name()); + pentry.set_tunnel_ip(entry->tunnel_ip().to_string()); + pswitch.push_back(pentry); + entry = static_cast(table->Next(entry)); + } + resp_->set_pswitch(pswitch); + SendResponse(); + return true; + } +private: + void SendResponse() { + resp_->set_context(resp_data_); + resp_->set_more(false); + resp_->Response(); + } + + OvsdbPhysicalSwitchResp *resp_; + std::string resp_data_; + DISALLOW_COPY_AND_ASSIGN(PhysicalSwitchSandeshTask); +}; + +void OvsdbPhysicalSwitchReq::HandleRequest() const { + PhysicalSwitchSandeshTask *task = new PhysicalSwitchSandeshTask(context()); + TaskScheduler *scheduler = TaskScheduler::GetInstance(); + scheduler->Enqueue(task); +} + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/physical_switch_ovsdb.h b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/physical_switch_ovsdb.h new file mode 100644 index 00000000000..cc37728d21c --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/physical_switch_ovsdb.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +#ifndef SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_PHYSICAL_SWITCH_OVSDB_H_ +#define SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_PHYSICAL_SWITCH_OVSDB_H_ + +#include +#include + +namespace OVSDB { +class PhysicalSwitchTable : public OvsdbObject { +public: + PhysicalSwitchTable(OvsdbClientIdl *idl); + virtual ~PhysicalSwitchTable(); + + void Notify(OvsdbClientIdl::Op, struct ovsdb_idl_row *); + KSyncEntry *Alloc(const KSyncEntry *key, uint32_t index); +private: + DISALLOW_COPY_AND_ASSIGN(PhysicalSwitchTable); +}; + +class PhysicalSwitchEntry : public OvsdbEntry { +public: + enum Trace { + ADD, + DEL, + }; + PhysicalSwitchEntry(PhysicalSwitchTable *table, const std::string &name); + ~PhysicalSwitchEntry(); + + Ip4Address &tunnel_ip(); + const std::string &name(); + void set_tunnel_ip(std::string ip); + bool IsLess(const KSyncEntry&) const; + std::string ToString() const {return "Physical Switch";} + KSyncEntry* UnresolvedReference(); +private: + void SendTrace(Trace event) const; + + friend class PhysicalSwitchTable; + std::string name_; + Ip4Address tunnel_ip_; + DISALLOW_COPY_AND_ASSIGN(PhysicalSwitchEntry); +}; +}; + +#endif //SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_PHYSICAL_SWITCH_OVSDB_H_ + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/test/SConscript b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/test/SConscript new file mode 100644 index 00000000000..738b40fbcf9 --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/test/SConscript @@ -0,0 +1,37 @@ +# +# Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. +# + +# -*- mode: python; -*- + +import sys +if sys.platform == 'darwin': + Return() + +import re +Import('AgentEnv') +env = AgentEnv.Clone() + +# test specific modifications +AgentEnv.MakeTestEnv(env) + +env.Append(LIBPATH = [ '../../../tables' ]) +env.Append(LIBPATH = ['./']) +env.Append(LIBPATH = ['../']) +env.Append(LIBS = [ 'physical_devices']) +env.Append(LIBS = [ 'control_node_mock']) +env.Prepend(LIBS = [ 'test_ovs_agent_init']) +env.Prepend(LIBS = [ 'ovsdbclient', 'openvswitch']) + +env.Library('test_ovs_agent_init', 'test_ovs_agent_init.cc') + +agent_suite = [] +flaky_agent_suite = [] +test_ovs_route = AgentEnv.MakeTestCmd(env, 'test_ovs_route', agent_suite) + +flaky_test = env.TestSuite('agent-flaky-test', flaky_agent_suite) +env.Alias('ovsdb_client:flaky_test', flaky_test) + +test = env.TestSuite('agent-test', agent_suite) +env.Alias('agent:agent_test', test) +Return('agent_suite') diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/test/test_ovs_agent_init.cc b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/test/test_ovs_agent_init.cc new file mode 100644 index 00000000000..6d3dafb991d --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/test/test_ovs_agent_init.cc @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "test/test_init.h" +#include +#include "test_ovs_agent_init.h" + +TestOvsAgentInit::TestOvsAgentInit() : TestAgentInit() { +} + +TestOvsAgentInit::~TestOvsAgentInit() { + device_manager_.reset(); +} + +/**************************************************************************** + * Initialization routines + ***************************************************************************/ +// Create the basic modules for agent operation. +// Optional modules or modules that have different implementation are created +// by init module +void TestOvsAgentInit::CreateModules() { + TestAgentInit::CreateModules(); + device_manager_.reset(new PhysicalDeviceManager(agent())); + agent()->set_device_manager(device_manager_.get()); +} + +void TestOvsAgentInit::CreateDBTables() { + TestAgentInit::CreateDBTables(); + device_manager_->CreateDBTables(agent()->db()); +} + +void TestOvsAgentInit::RegisterDBClients() { + TestAgentInit::RegisterDBClients(); + device_manager_->RegisterDBClients(); +} + +void TestOvsAgentInit::CreatePeers() { + ovs_peer_manager_.reset(new OvsPeerManager(agent())); +} + +/**************************************************************************** + * Access routines + ****************************************************************************/ +PhysicalDeviceManager *TestOvsAgentInit::device_manager() const { + return device_manager_.get(); +} + +OvsPeerManager *TestOvsAgentInit::ovs_peer_manager() const { + return ovs_peer_manager_.get(); +} + +TestClient *OvsTestInit(const char *init_file, bool ksync_init) { + TestClient *client = new TestClient(new TestOvsAgentInit()); + TestOvsAgentInit *init = + static_cast(client->agent_init()); + Agent *agent = client->agent(); + + AgentParam *param = client->param(); + init->set_agent_param(param); + // Read agent parameters from config file and arguments + init->ProcessOptions(init_file, "test"); + param->set_agent_stats_interval(AgentParam::kAgentStatsInterval); + param->set_flow_stats_interval(AgentParam::kFlowStatsInterval); + param->set_vrouter_stats_interval(AgentParam::kVrouterStatsInterval); + + // Initialize the agent-init control class + int introspect_port = 0; + Sandesh::InitGeneratorTest("VNSWAgent", "Agent", "Test", "Test", + agent->event_manager(), introspect_port, NULL); + + init->set_ksync_enable(false); + init->set_packet_enable(true); + init->set_services_enable(true); + init->set_create_vhost(false); + init->set_uve_enable(true); + init->set_vgw_enable(false); + init->set_router_id_dep_enable(false); + param->set_test_mode(true); + agent->set_ksync_sync_mode(true); + + // Initialize agent and kick start initialization + init->Start(); + WaitForInitDone(agent); + + client->Init(); + client->WaitForIdle(); + client->SetFlowFlushExclusionPolicy(); + client->SetFlowAgeExclusionPolicy(); + + AsioRun(); + + return client; +} diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/test/test_ovs_agent_init.h b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/test/test_ovs_agent_init.h new file mode 100644 index 00000000000..114966ee195 --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/test/test_ovs_agent_init.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. + */ + +#ifndef vnsw_test_ovs_agent_init_hpp +#define vnsw_test_ovs_agent_init_hpp + +#include +#include +#include +#include + +class Agent; +class AgentParam; +class TestClient; +class OvsPeerManager; + +TestClient *OvsTestInit(const char *init_file, bool ksync_init); + +// The class to drive agent initialization. +// Defines control parameters used to enable/disable agent features +class TestOvsAgentInit : public TestAgentInit { +public: + TestOvsAgentInit(); + virtual ~TestOvsAgentInit(); + + void CreatePeers(); + void CreateModules(); + void CreateDBTables(); + void RegisterDBClients(); + + PhysicalDeviceManager *device_manager() const; + OvsPeerManager *ovs_peer_manager() const; +private: + std::auto_ptr device_manager_; + std::auto_ptr ovs_peer_manager_; + DISALLOW_COPY_AND_ASSIGN(TestOvsAgentInit); +}; + +#endif // vnsw_test_ovs_agent_init_hpp diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/test/test_ovs_route.cc b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/test/test_ovs_route.cc new file mode 100644 index 00000000000..c4107fc09e0 --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/test/test_ovs_route.cc @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. + */ + +#include "base/os.h" +#include "testing/gunit.h" + +#include +#include +#include +#include +#include + +#include + +#include "cfg/cfg_init.h" +#include "cfg/cfg_interface.h" +#include "pkt/pkt_init.h" +#include "services/services_init.h" +#include "ksync/ksync_init.h" +#include "oper/interface_common.h" +#include "oper/nexthop.h" +#include "oper/tunnel_nh.h" +#include "route/route.h" +#include "oper/vrf.h" +#include "oper/mpls.h" +#include "oper/vm.h" +#include "oper/vn.h" +#include "filter/acl.h" +#include "openstack/instance_service_server.h" +#include "test_cmn_util.h" +#include "vr_types.h" + +#include "openstack/instance_service_server.h" +#include "xmpp/xmpp_init.h" +#include "xmpp/test/xmpp_test_util.h" +#include "vr_types.h" +#include "control_node_mock.h" +#include "xml/xml_pugi.h" +#include "controller/controller_peer.h" +#include "controller/controller_export.h" +#include "controller/controller_vrf_export.h" + +#include "physical_devices/ovs_tor_agent/ovsdb_client/ovsdb_route_peer.h" +#include "test_ovs_agent_init.h" + +using namespace pugi; + +EventManager evm1; +ServerThread *thread1; +test::ControlNodeMock *bgp_peer1; + +EventManager evm2; +ServerThread *thread2; +test::ControlNodeMock *bgp_peer2; + +void RouterIdDepInit(Agent *agent) { + Agent::GetInstance()->controller()->Connect(); +} + +void StartControlNodeMock() { + thread1 = new ServerThread(&evm1); + bgp_peer1 = new test::ControlNodeMock(&evm1, "127.0.0.1"); + + Agent::GetInstance()->set_controller_ifmap_xmpp_server("127.0.0.1", 0); + Agent::GetInstance()->set_controller_ifmap_xmpp_port(bgp_peer1->GetServerPort(), 0); + Agent::GetInstance()->set_dns_server("", 0); + Agent::GetInstance()->set_dns_server_port(bgp_peer1->GetServerPort(), 0); + thread1->Start(); +} + +void StopControlNodeMock() { + Agent::GetInstance()->controller()->DisConnect(); + client->WaitForIdle(); + TcpServerManager::DeleteServer(Agent::GetInstance()->controller_ifmap_xmpp_client(0)); + + bgp_peer1->Shutdown(); + client->WaitForIdle(); + delete bgp_peer1; + + evm1.Shutdown(); + thread1->Join(); + delete thread1; + + client->WaitForIdle(); +} + +class OvsRouteTest : public ::testing::Test { +protected: + OvsRouteTest() { + } + + virtual void SetUp() { + agent_ = Agent::GetInstance(); + init_ = static_cast(client->agent_init()); + peer_manager_ = init_->ovs_peer_manager(); + client->Reset(); + } + + virtual void TearDown() { + //Clean up any pending routes in conrol node mock + bgp_peer1->Clear(); + EXPECT_EQ(peer_manager_->Size(), 0); + } + + Agent *agent_; + TestOvsAgentInit *init_; + OvsPeerManager *peer_manager_; +}; + +TEST_F(OvsRouteTest, OvsPeer_1) { + IpAddress server = Ip4Address::from_string("1.1.1.1"); + OvsPeer *peer = peer_manager_->Allocate(server); + EXPECT_TRUE(peer->export_to_controller()); + peer_manager_->Free(peer); +} + +TEST_F(OvsRouteTest, RouteTest_1) { +} + +int main(int argc, char *argv[]) { + //::testing::InitGoogleTest(&argc, argv); + GETUSERARGS(); + client = OvsTestInit(init_file, ksync_init); + StartControlNodeMock(); + int ret = RUN_ALL_TESTS(); + StopControlNodeMock(); + + return ret; +} diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/unicast_mac_local_ovsdb.cc b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/unicast_mac_local_ovsdb.cc new file mode 100644 index 00000000000..c75c962c736 --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/unicast_mac_local_ovsdb.cc @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +extern "C" { +#include +}; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace AGENT; +using OVSDB::UnicastMacLocalOvsdb; +using OVSDB::UnicastMacLocalEntry; +using OVSDB::OvsdbClientSession; +using std::string; + +UnicastMacLocalEntry::UnicastMacLocalEntry(UnicastMacLocalOvsdb *table, + const UnicastMacLocalEntry *key) : OvsdbEntry(table), mac_(key->mac_), + logical_switch_name_(key->logical_switch_name_), dest_ip_(key->dest_ip_) { + LogicalSwitchTable *l_table = table_->client_idl()->logical_switch_table(); + LogicalSwitchEntry l_key(l_table, logical_switch_name_.c_str()); + logical_switch_ = l_table->GetReference(&l_key); +} + +UnicastMacLocalEntry::UnicastMacLocalEntry(UnicastMacLocalOvsdb *table, + struct ovsdb_idl_row *row) : OvsdbEntry(table), + mac_(ovsdb_wrapper_ucast_mac_local_mac(row)), + logical_switch_name_(ovsdb_wrapper_ucast_mac_local_logical_switch(row)), + dest_ip_() { + if (ovsdb_wrapper_ucast_mac_local_dst_ip(row)) + dest_ip_ = ovsdb_wrapper_ucast_mac_local_dst_ip(row); +} + +UnicastMacLocalEntry::~UnicastMacLocalEntry() { +} + +bool UnicastMacLocalEntry::Add() { + UnicastMacLocalOvsdb *table = static_cast(table_); + OVSDB_TRACE(Trace, "Adding Route " + mac_ + " VN uuid " + + logical_switch_name_ + " destination IP " + dest_ip_); + boost::uuids::uuid ls_uuid = StringToUuid(logical_switch_name_); + boost::system::error_code err; + Ip4Address dest = Ip4Address::from_string(dest_ip_, err); + table->peer()->AddOvsRoute(ls_uuid, MacAddress(mac_), dest); + return true; +} + +bool UnicastMacLocalEntry::Delete() { + UnicastMacLocalOvsdb *table = static_cast(table_); + OVSDB_TRACE(Trace, "Deleting Route " + mac_ + " VN uuid " + + logical_switch_name_ + " destination IP " + dest_ip_); + LogicalSwitchEntry *ls_entry = + static_cast(logical_switch_.get()); + const PhysicalDeviceVnEntry *dev_vn = + static_cast(ls_entry->GetDBEntry()); + table->peer()->DeleteOvsRoute(dev_vn->vn(), MacAddress(mac_)); + return true; +} + +bool UnicastMacLocalEntry::IsLess(const KSyncEntry& entry) const { + const UnicastMacLocalEntry &ucast = + static_cast(entry); + if (mac_ != ucast.mac_) + return mac_ < ucast.mac_; + return logical_switch_name_ < ucast.logical_switch_name_; +} + +KSyncEntry *UnicastMacLocalEntry::UnresolvedReference() { + LogicalSwitchTable *l_table = table_->client_idl()->logical_switch_table(); + LogicalSwitchEntry key(l_table, logical_switch_name_.c_str()); + LogicalSwitchEntry *l_switch = + static_cast(l_table->GetReference(&key)); + if (!l_switch->IsResolved()) { + return l_switch; + } + return NULL; +} + +const std::string &UnicastMacLocalEntry::mac() const { + return mac_; +} + +const std::string &UnicastMacLocalEntry::logical_switch_name() const { + return logical_switch_name_; +} + +const std::string &UnicastMacLocalEntry::dest_ip() const { + return dest_ip_; +} + +UnicastMacLocalOvsdb::UnicastMacLocalOvsdb(OvsdbClientIdl *idl, OvsPeer *peer) : + OvsdbObject(idl), peer_(peer) { + idl->Register(OvsdbClientIdl::OVSDB_UCAST_MAC_LOCAL, + boost::bind(&UnicastMacLocalOvsdb::Notify, this, _1, _2)); +} + +UnicastMacLocalOvsdb::~UnicastMacLocalOvsdb() { + client_idl_->UnRegister(OvsdbClientIdl::OVSDB_UCAST_MAC_LOCAL); +} + +OvsPeer *UnicastMacLocalOvsdb::peer() { + return peer_; +} + +void UnicastMacLocalOvsdb::Notify(OvsdbClientIdl::Op op, + struct ovsdb_idl_row *row) { + const char *ls_name = ovsdb_wrapper_ucast_mac_local_logical_switch(row); + const char *dest_ip = ovsdb_wrapper_ucast_mac_local_dst_ip(row); + /* ignore if ls_name is not present */ + if (ls_name == NULL) { + return; + } + UnicastMacLocalEntry key(this, row); + UnicastMacLocalEntry *entry = + static_cast(FindActiveEntry(&key)); + /* trigger delete if dest ip is not available */ + if (op == OvsdbClientIdl::OVSDB_DEL || dest_ip == NULL) { + if (entry != NULL) { + Delete(entry); + } + } else if (op == OvsdbClientIdl::OVSDB_ADD) { + if (entry == NULL) { + entry = static_cast(Create(&key)); + } + } else { + assert(0); + } +} + +KSyncEntry *UnicastMacLocalOvsdb::Alloc(const KSyncEntry *key, uint32_t index) { + const UnicastMacLocalEntry *k_entry = + static_cast(key); + UnicastMacLocalEntry *entry = new UnicastMacLocalEntry(this, k_entry); + return entry; +} + +///////////////////////////////////////////////////////////////////////////// +// Sandesh routines +///////////////////////////////////////////////////////////////////////////// +class UnicastMacLocalSandeshTask : public Task { +public: + UnicastMacLocalSandeshTask(std::string resp_ctx) : + Task((TaskScheduler::GetInstance()->GetTaskId("Agent::KSync")), -1), + resp_(new OvsdbUnicastMacLocalResp()), resp_data_(resp_ctx) { + } + virtual ~UnicastMacLocalSandeshTask() {} + virtual bool Run() { + std::vector macs; + TorAgentInit *init = + static_cast(Agent::GetInstance()->agent_init()); + OvsdbClientSession *session = init->ovsdb_client()->next_session(NULL); + UnicastMacLocalOvsdb *table = + session->client_idl()->unicast_mac_local_ovsdb(); + UnicastMacLocalEntry *entry = + static_cast(table->Next(NULL)); + while (entry != NULL) { + OvsdbUnicastMacLocalEntry oentry; + oentry.set_state(entry->StateString()); + oentry.set_mac(entry->mac()); + oentry.set_logical_switch(entry->logical_switch_name()); + oentry.set_dest_ip(entry->dest_ip()); + macs.push_back(oentry); + entry = static_cast(table->Next(entry)); + } + resp_->set_macs(macs); + SendResponse(); + return true; + } +private: + void SendResponse() { + resp_->set_context(resp_data_); + resp_->set_more(false); + resp_->Response(); + } + + OvsdbUnicastMacLocalResp *resp_; + std::string resp_data_; + DISALLOW_COPY_AND_ASSIGN(UnicastMacLocalSandeshTask); +}; + +void OvsdbUnicastMacLocalReq::HandleRequest() const { + UnicastMacLocalSandeshTask *task = new UnicastMacLocalSandeshTask(context()); + TaskScheduler *scheduler = TaskScheduler::GetInstance(); + scheduler->Enqueue(task); +} + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/unicast_mac_local_ovsdb.h b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/unicast_mac_local_ovsdb.h new file mode 100644 index 00000000000..29e56098dd8 --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/unicast_mac_local_ovsdb.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +#ifndef SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVSDB_ROUTE_H_ +#define SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVSDB_ROUTE_H_ + +#include +#include +class OvsPeer; + +namespace OVSDB { +class UnicastMacLocalOvsdb : public OvsdbObject { +public: + UnicastMacLocalOvsdb(OvsdbClientIdl *idl, OvsPeer *peer); + ~UnicastMacLocalOvsdb(); + + OvsPeer *peer(); + void Notify(OvsdbClientIdl::Op op, struct ovsdb_idl_row *row); + KSyncEntry *Alloc(const KSyncEntry *key, uint32_t index); + +private: + OvsPeer *peer_; + DISALLOW_COPY_AND_ASSIGN(UnicastMacLocalOvsdb); +}; + +class UnicastMacLocalEntry : public OvsdbEntry { +public: + UnicastMacLocalEntry(UnicastMacLocalOvsdb *table, + const UnicastMacLocalEntry *key); + UnicastMacLocalEntry(UnicastMacLocalOvsdb *table, + struct ovsdb_idl_row *row); + ~UnicastMacLocalEntry(); + + bool Add(); + bool Delete(); + bool IsLess(const KSyncEntry&) const; + KSyncEntry* UnresolvedReference(); + std::string ToString() const {return "Unicast Mac Local";} + + const std::string &mac() const; + const std::string &logical_switch_name() const; + const std::string &dest_ip() const; + +private: + friend class UnicastMacLocalOvsdb; + std::string mac_; + std::string logical_switch_name_; + std::string dest_ip_; + KSyncEntryPtr logical_switch_; + DISALLOW_COPY_AND_ASSIGN(UnicastMacLocalEntry); +}; + +}; + +#endif //SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_OVSDB_ROUTE_H_ + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/unicast_mac_remote_ovsdb.cc b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/unicast_mac_remote_ovsdb.cc new file mode 100644 index 00000000000..03575b84b1e --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/unicast_mac_remote_ovsdb.cc @@ -0,0 +1,438 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +extern "C" { +#include +}; +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace AGENT; +using OVSDB::UnicastMacRemoteEntry; +using OVSDB::UnicastMacRemoteTable; +using OVSDB::VrfOvsdbObject; +using OVSDB::OvsdbDBEntry; +using OVSDB::OvsdbDBObject; +using OVSDB::OvsdbClientSession; + +UnicastMacRemoteEntry::UnicastMacRemoteEntry(OvsdbDBObject *table, + const std::string mac, const std::string logical_switch) : + OvsdbDBEntry(table), mac_(mac), logical_switch_name_(logical_switch), + self_exported_route_(false) { +} + +UnicastMacRemoteEntry::UnicastMacRemoteEntry(OvsdbDBObject *table, + const Layer2RouteEntry *entry) : OvsdbDBEntry(table), + mac_(entry->GetAddress().ToString()), + logical_switch_name_(UuidToString(entry->vrf()->vn()->GetUuid())) { +} + +UnicastMacRemoteEntry::UnicastMacRemoteEntry(OvsdbDBObject *table, + const UnicastMacRemoteEntry *entry) : OvsdbDBEntry(table), + mac_(entry->mac_), logical_switch_name_(entry->logical_switch_name_), + dest_ip_(entry->dest_ip_) { +} + +UnicastMacRemoteEntry::UnicastMacRemoteEntry(OvsdbDBObject *table, + struct ovsdb_idl_row *entry) : OvsdbDBEntry(table, entry), + mac_(ovsdb_wrapper_ucast_mac_remote_mac(entry)), + logical_switch_name_(ovsdb_wrapper_ucast_mac_remote_logical_switch(entry)), + dest_ip_() { + const char *dest_ip = ovsdb_wrapper_ucast_mac_remote_dst_ip(entry); + if (dest_ip) { + dest_ip_ = std::string(dest_ip); + } +}; + +void UnicastMacRemoteEntry::PreAddChange() { + if (self_exported_route_) { + return; + } + LogicalSwitchTable *l_table = table_->client_idl()->logical_switch_table(); + LogicalSwitchEntry key(l_table, logical_switch_name_.c_str()); + LogicalSwitchEntry *logical_switch = + static_cast(l_table->GetReference(&key)); + logical_switch_ = logical_switch; +} + +void UnicastMacRemoteEntry::PostDelete() { + logical_switch_ = NULL; +} + +void UnicastMacRemoteEntry::AddMsg(struct ovsdb_idl_txn *txn) { + boost::system::error_code ec; + Ip4Address dest_ip = Ip4Address::from_string(dest_ip_, ec); + LogicalSwitchEntry *logical_switch = + static_cast(logical_switch_.get()); + if (self_exported_route_ || + dest_ip == logical_switch->physical_switch_tunnel_ip()) { + // if the route is self exported or if dest tunnel end-point points to + // the physical switch itself then donot export this route to OVSDB + DeleteMsg(txn); + return; + } + if (ovs_entry_ == NULL && !dest_ip_.empty()) { + PhysicalLocatorTable *pl_table = + table_->client_idl()->physical_locator_table(); + PhysicalLocatorEntry pl_key(pl_table, dest_ip_); + /* + * we don't take reference to physical locator, just use if locator + * is existing or we will create a new one. + */ + PhysicalLocatorEntry *pl_entry = + static_cast(pl_table->Find(&pl_key)); + struct ovsdb_idl_row *pl_row = NULL; + if (pl_entry) + pl_row = pl_entry->ovs_entry(); + obvsdb_wrapper_add_ucast_mac_remote(txn, mac_.c_str(), + logical_switch->ovs_entry(), pl_row, dest_ip_.c_str()); + SendTrace(UnicastMacRemoteEntry::ADD_REQ); + } +} + +void UnicastMacRemoteEntry::ChangeMsg(struct ovsdb_idl_txn *txn) { + AddMsg(txn); +} + +void UnicastMacRemoteEntry::DeleteMsg(struct ovsdb_idl_txn *txn) { + if (ovs_entry_) { + ovsdb_wrapper_delete_ucast_mac_remote(ovs_entry_); + SendTrace(UnicastMacRemoteEntry::DEL_REQ); + } +} + +void UnicastMacRemoteEntry::OvsdbChange() { + if (!IsResolved()) + table_->NotifyEvent(this, KSyncEntry::ADD_CHANGE_REQ); +} + +bool UnicastMacRemoteEntry::Sync(DBEntry *db_entry) { + const Layer2RouteEntry *entry = + static_cast(db_entry); + std::string dest_ip; + const NextHop *nh = entry->GetActiveNextHop(); + /* + * TOR Agent will not have any local VM so only tunnel nexthops + * are to be looked into + */ + if (nh && nh->GetType() == NextHop::TUNNEL) { + /* + * we don't care the about the tunnel type in nh and always program + * the entry to ovsdb expecting vrouter to always handle + * VxLAN encapsulation. + */ + const TunnelNH *tunnel = static_cast(nh); + dest_ip = tunnel->GetDip()->to_string(); + } + bool change = false; + if (dest_ip_ != dest_ip) { + dest_ip_ = dest_ip; + change = true; + } + bool self_exported_route = + (entry->FindPath((Peer *)table_->client_idl()->route_peer()) != NULL); + if (self_exported_route_ != self_exported_route) { + self_exported_route_ = self_exported_route; + change = true; + } + return change; +} + +bool UnicastMacRemoteEntry::IsLess(const KSyncEntry &entry) const { + const UnicastMacRemoteEntry &ucast = + static_cast(entry); + if (mac_ != ucast.mac_) + return mac_ < ucast.mac_; + return logical_switch_name_ < ucast.logical_switch_name_; +} + +KSyncEntry *UnicastMacRemoteEntry::UnresolvedReference() { + LogicalSwitchTable *l_table = table_->client_idl()->logical_switch_table(); + LogicalSwitchEntry key(l_table, logical_switch_name_.c_str()); + LogicalSwitchEntry *l_switch = + static_cast(l_table->GetReference(&key)); + if (!l_switch->IsResolved()) { + return l_switch; + } + return NULL; +} + +const std::string &UnicastMacRemoteEntry::mac() const { + return mac_; +} + +const std::string &UnicastMacRemoteEntry::logical_switch_name() const { + return logical_switch_name_; +} + +const std::string &UnicastMacRemoteEntry::dest_ip() const { + return dest_ip_; +} + +bool UnicastMacRemoteEntry::self_exported_route() const { + return self_exported_route_; +} + +void UnicastMacRemoteEntry::SendTrace(Trace event) const { + SandeshUnicastMacRemoteInfo info; + switch (event) { + case ADD_REQ: + info.set_op("Add Requested"); + break; + case DEL_REQ: + info.set_op("Delete Requested"); + break; + case ADD_ACK: + info.set_op("Add Received"); + break; + case DEL_ACK: + info.set_op("Delete Received"); + break; + default: + info.set_op("unknown"); + } + info.set_mac(mac_); + info.set_logical_switch(logical_switch_name_); + info.set_dest_ip(dest_ip_); + OVSDB_TRACE(UnicastMacRemote, info); +} + +UnicastMacRemoteTable::UnicastMacRemoteTable(OvsdbClientIdl *idl, + AgentRouteTable *table) : OvsdbDBObject(idl, table), + table_delete_ref_(this, table->deleter()) { +} + +UnicastMacRemoteTable::~UnicastMacRemoteTable() { + // explicit unregister required before removing the reference, to assure + // pointer sanity. + UnregisterDb(GetDBTable()); + table_delete_ref_.Reset(NULL); +} + +void UnicastMacRemoteTable::OvsdbNotify(OvsdbClientIdl::Op op, + struct ovsdb_idl_row *row) { + const char *mac = ovsdb_wrapper_ucast_mac_remote_mac(row); + const char *logical_switch = + ovsdb_wrapper_ucast_mac_remote_logical_switch(row); + /* if logical switch is not available ignore nodtification */ + if (logical_switch == NULL) + return; + const char *dest_ip = ovsdb_wrapper_ucast_mac_remote_dst_ip(row); + UnicastMacRemoteEntry key(this, mac, logical_switch); + if (op == OvsdbClientIdl::OVSDB_DEL) { + NotifyDeleteOvsdb((OvsdbDBEntry*)&key); + if (dest_ip) + key.dest_ip_ = std::string(dest_ip); + key.SendTrace(UnicastMacRemoteEntry::DEL_ACK); + } else if (op == OvsdbClientIdl::OVSDB_ADD) { + NotifyAddOvsdb((OvsdbDBEntry*)&key, row); + if (dest_ip) + key.dest_ip_ = std::string(dest_ip); + key.SendTrace(UnicastMacRemoteEntry::ADD_ACK); + } else { + assert(0); + } +} + +KSyncEntry *UnicastMacRemoteTable::Alloc(const KSyncEntry *key, uint32_t index) { + const UnicastMacRemoteEntry *k_entry = + static_cast(key); + UnicastMacRemoteEntry *entry = new UnicastMacRemoteEntry(this, k_entry); + return entry; +} + +KSyncEntry *UnicastMacRemoteTable::DBToKSyncEntry(const DBEntry* db_entry) { + const Layer2RouteEntry *entry = + static_cast(db_entry); + UnicastMacRemoteEntry *key = new UnicastMacRemoteEntry(this, entry); + return static_cast(key); +} + +OvsdbDBEntry *UnicastMacRemoteTable::AllocOvsEntry(struct ovsdb_idl_row *row) { + UnicastMacRemoteEntry key(this, row); + return static_cast(Create(&key)); +} + +void UnicastMacRemoteTable::ManagedDelete() { + deleted_ = true; + Unregister(); +} + +void UnicastMacRemoteTable::Unregister() { + if (IsEmpty() == true && deleted_ == true) { + KSyncObjectManager::Unregister(this); + } +} + +void UnicastMacRemoteTable::EmptyTable() { + if (deleted_ == true) { + Unregister(); + } +} + +void UnicastMacRemoteTable::set_deleted(bool deleted) { + deleted_ = deleted; +} + +bool UnicastMacRemoteTable::deleted() { + return deleted_; +} + +VrfOvsdbObject::VrfOvsdbObject(OvsdbClientIdl *idl, DBTable *table) : + client_idl_(idl), table_(table) { + vrf_listener_id_ = table->Register(boost::bind(&VrfOvsdbObject::VrfNotify, + this, _1, _2)); + client_idl_->Register(OvsdbClientIdl::OVSDB_UCAST_MAC_REMOTE, + boost::bind(&VrfOvsdbObject::OvsdbRouteNotify, this, _1, _2)); +} + +VrfOvsdbObject::~VrfOvsdbObject() { + table_->Unregister(vrf_listener_id_); + client_idl_->UnRegister(OvsdbClientIdl::OVSDB_UCAST_MAC_REMOTE); +} + +void VrfOvsdbObject::OvsdbRouteNotify(OvsdbClientIdl::Op op, + struct ovsdb_idl_row *row) { + const char *mac = ovsdb_wrapper_ucast_mac_remote_mac(row); + const char *logical_switch = + ovsdb_wrapper_ucast_mac_remote_logical_switch(row); + /* if logical switch is not available ignore notification */ + if (logical_switch == NULL) + return; + LogicalSwitchMap::iterator it = logical_switch_map_.find(logical_switch); + if (it == logical_switch_map_.end()) { + // if we fail to find ksync object, encode and send delete. + struct ovsdb_idl_txn *txn = client_idl_->CreateTxn(NULL); + ovsdb_wrapper_delete_ucast_mac_remote(row); + struct jsonrpc_msg *msg = ovsdb_wrapper_idl_txn_encode(txn); + if (msg == NULL) { + client_idl_->DeleteTxn(txn); + } else { + client_idl_->SendJsonRpc(msg); + } + return; + } + const char *dest_ip = ovsdb_wrapper_ucast_mac_remote_dst_ip(row); + UnicastMacRemoteTable *table= it->second->l2_table; + UnicastMacRemoteEntry key(table, mac, logical_switch); + if (op == OvsdbClientIdl::OVSDB_DEL) { + table->NotifyDeleteOvsdb((OvsdbDBEntry*)&key); + if (dest_ip) + key.dest_ip_ = std::string(dest_ip); + key.SendTrace(UnicastMacRemoteEntry::DEL_ACK); + } else if (op == OvsdbClientIdl::OVSDB_ADD) { + table->NotifyAddOvsdb((OvsdbDBEntry*)&key, row); + if (dest_ip) + key.dest_ip_ = std::string(dest_ip); + key.SendTrace(UnicastMacRemoteEntry::ADD_ACK); + } else { + assert(0); + } +} + +void VrfOvsdbObject::VrfNotify(DBTablePartBase *partition, DBEntryBase *e) { + VrfEntry *vrf = static_cast(e); + VrfState *state = static_cast + (vrf->GetState(partition->parent(), vrf_listener_id_)); + if (vrf->IsDeleted()) { + if (state) { + logical_switch_map_.erase(state->logical_switch_name_); + vrf->ClearState(partition->parent(), vrf_listener_id_); + delete state; + } + return; + } + + if (vrf->vn() == NULL) { + return; + } + + if (state == NULL) { + state = new VrfState(); + state->logical_switch_name_ = UuidToString(vrf->vn()->GetUuid()); + // Assumption one vn maps only to one vrf + logical_switch_map_[state->logical_switch_name_] = state; + vrf->SetState(partition->parent(), vrf_listener_id_, state); + + /* We are interested only in L2 Routes */ + state->l2_table = new UnicastMacRemoteTable(client_idl_, + vrf->GetLayer2RouteTable()); + } +} + +const VrfOvsdbObject::LogicalSwitchMap & +VrfOvsdbObject::logical_switch_map() const { + return logical_switch_map_; +} + +///////////////////////////////////////////////////////////////////////////// +// Sandesh routines +///////////////////////////////////////////////////////////////////////////// +class UnicastMacRemoteSandeshTask : public Task { +public: + UnicastMacRemoteSandeshTask(std::string resp_ctx) : + Task((TaskScheduler::GetInstance()->GetTaskId("Agent::KSync")), -1), + resp_(new OvsdbUnicastMacRemoteResp()), resp_data_(resp_ctx) { + } + virtual ~UnicastMacRemoteSandeshTask() {} + virtual bool Run() { + std::vector macs; + TorAgentInit *init = + static_cast(Agent::GetInstance()->agent_init()); + OvsdbClientSession *session = init->ovsdb_client()->next_session(NULL); + VrfOvsdbObject *vrf_obj = session->client_idl()->vrf_ovsdb(); + const VrfOvsdbObject::LogicalSwitchMap ls_table = + vrf_obj->logical_switch_map(); + VrfOvsdbObject::LogicalSwitchMap::const_iterator it = ls_table.begin(); + for (; it != ls_table.end(); it++) { + UnicastMacRemoteTable *table = it->second->l2_table; + UnicastMacRemoteEntry *entry = + static_cast(table->Next(NULL)); + while (entry != NULL) { + OvsdbUnicastMacRemoteEntry oentry; + oentry.set_state(entry->StateString()); + oentry.set_mac(entry->mac()); + oentry.set_logical_switch(entry->logical_switch_name()); + oentry.set_dest_ip(entry->dest_ip()); + oentry.set_self_exported(entry->self_exported_route()); + macs.push_back(oentry); + entry = static_cast(table->Next(entry)); + } + } + resp_->set_macs(macs); + SendResponse(); + return true; + } +private: + void SendResponse() { + resp_->set_context(resp_data_); + resp_->set_more(false); + resp_->Response(); + } + + OvsdbUnicastMacRemoteResp *resp_; + std::string resp_data_; + DISALLOW_COPY_AND_ASSIGN(UnicastMacRemoteSandeshTask); +}; + +void OvsdbUnicastMacRemoteReq::HandleRequest() const { + UnicastMacRemoteSandeshTask *task = + new UnicastMacRemoteSandeshTask(context()); + TaskScheduler *scheduler = TaskScheduler::GetInstance(); + scheduler->Enqueue(task); +} + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/unicast_mac_remote_ovsdb.h b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/unicast_mac_remote_ovsdb.h new file mode 100644 index 00000000000..5dae50a4974 --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/unicast_mac_remote_ovsdb.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +#ifndef SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_UNICAST_MAC_REMOTE_OVSDB_H_ +#define SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_UNICAST_MAC_REMOTE_OVSDB_H_ + +#include +#include +#include +#include + +class Layer2RouteEntry; + +namespace OVSDB { +class VrfOvsdbObject; + +class UnicastMacRemoteTable : public OvsdbDBObject { +public: + UnicastMacRemoteTable(OvsdbClientIdl *idl, AgentRouteTable *table); + virtual ~UnicastMacRemoteTable(); + + void OvsdbNotify(OvsdbClientIdl::Op, struct ovsdb_idl_row *); + + KSyncEntry *Alloc(const KSyncEntry *key, uint32_t index); + KSyncEntry *DBToKSyncEntry(const DBEntry*); + OvsdbDBEntry *AllocOvsEntry(struct ovsdb_idl_row *row); + void ManagedDelete(); + void Unregister(); + virtual void EmptyTable(); + + void set_deleted(bool deleted); + bool deleted(); + +private: + bool deleted_; + LifetimeRef table_delete_ref_; + DISALLOW_COPY_AND_ASSIGN(UnicastMacRemoteTable); +}; + +class UnicastMacRemoteEntry : public OvsdbDBEntry { +public: + enum Trace { + ADD_REQ, + DEL_REQ, + ADD_ACK, + DEL_ACK, + }; + UnicastMacRemoteEntry(OvsdbDBObject *table, const std::string mac, + const std::string logical_switch); + UnicastMacRemoteEntry(OvsdbDBObject *table, const Layer2RouteEntry *entry); + UnicastMacRemoteEntry(OvsdbDBObject *table, const UnicastMacRemoteEntry *key); + UnicastMacRemoteEntry(OvsdbDBObject *table, + struct ovsdb_idl_row *entry); + + void PreAddChange(); + void PostDelete(); + void AddMsg(struct ovsdb_idl_txn *); + void ChangeMsg(struct ovsdb_idl_txn *); + void DeleteMsg(struct ovsdb_idl_txn *); + + void OvsdbChange(); + + bool Sync(DBEntry*); + bool IsLess(const KSyncEntry&) const; + std::string ToString() const {return "Unicast Mac Remote";} + KSyncEntry* UnresolvedReference(); + + const std::string &mac() const; + const std::string &logical_switch_name() const; + const std::string &dest_ip() const; + bool self_exported_route() const; + +private: + friend class UnicastMacRemoteTable; + friend class VrfOvsdbObject; + void SendTrace(Trace event) const; + std::string mac_; + std::string logical_switch_name_; + std::string dest_ip_; + bool self_exported_route_; + KSyncEntryPtr logical_switch_; + DISALLOW_COPY_AND_ASSIGN(UnicastMacRemoteEntry); +}; + +class VrfOvsdbObject { +public: + struct VrfState : DBState { + std::string logical_switch_name_; + UnicastMacRemoteTable *l2_table; + }; + typedef std::map LogicalSwitchMap; + + VrfOvsdbObject(OvsdbClientIdl *idl, DBTable *table); + virtual ~VrfOvsdbObject(); + + void OvsdbRouteNotify(OvsdbClientIdl::Op, struct ovsdb_idl_row *); + + void VrfNotify(DBTablePartBase *partition, DBEntryBase *e); + const LogicalSwitchMap &logical_switch_map() const; + +private: + OvsdbClientIdl *client_idl_; + DBTable *table_; + LogicalSwitchMap logical_switch_map_; + DBTableBase::ListenerId vrf_listener_id_; + DISALLOW_COPY_AND_ASSIGN(VrfOvsdbObject); +}; + +}; + +#endif //SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_UNICAST_MAC_REMOTE_OVSDB_H_ + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/vlan_port_binding_ovsdb.cc b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/vlan_port_binding_ovsdb.cc new file mode 100644 index 00000000000..9bda710af64 --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/vlan_port_binding_ovsdb.cc @@ -0,0 +1,316 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +extern "C" { +#include +}; +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using OVSDB::OvsdbDBEntry; +using OVSDB::VlanPortBindingEntry; +using OVSDB::VlanPortBindingTable; +using OVSDB::PhysicalSwitchEntry; +using OVSDB::PhysicalPortEntry; +using OVSDB::LogicalSwitchEntry; +using OVSDB::OvsdbClientSession; + +VlanPortBindingEntry::VlanPortBindingEntry(VlanPortBindingTable *table, + const AGENT::VlanLogicalPortEntry *entry) : OvsdbDBEntry(table_), + logical_switch_name_(), physical_port_name_(entry->physical_port()->name()), + physical_device_name_(entry->physical_port()->device()->name()), + vlan_(entry->vlan()) { +} + +VlanPortBindingEntry::VlanPortBindingEntry(VlanPortBindingTable *table, + const VlanPortBindingEntry *key) : OvsdbDBEntry(table), + physical_port_name_(key->physical_port_name_), + physical_device_name_(key->physical_device_name_), vlan_(key->vlan_) { +} + +void VlanPortBindingEntry::PreAddChange() { + if (!logical_switch_name_.empty()) { + LogicalSwitchTable *l_table = + table_->client_idl()->logical_switch_table(); + LogicalSwitchEntry ls_key(l_table, logical_switch_name_.c_str()); + logical_switch_ = l_table->GetReference(&ls_key); + } else { + logical_switch_ = NULL; + } +} + +void VlanPortBindingEntry::PostDelete() { + logical_switch_ = NULL; +} + +void VlanPortBindingEntry::AddMsg(struct ovsdb_idl_txn *txn) { + PhysicalPortTable *p_table = table_->client_idl()->physical_port_table(); + PhysicalPortEntry key(p_table, physical_port_name_.c_str()); + physical_port_ = p_table->GetReference(&key); + PhysicalPortEntry *port = + static_cast(physical_port_.get()); + + if (!logical_switch_name_.empty()) { + port->AddBinding(vlan_, + static_cast(logical_switch_.get())); + OVSDB_TRACE(Trace, "Adding port vlan binding port " + + physical_port_name_ + " vlan " + integerToString(vlan_) + + " to Logical Switch " + logical_switch_name_); + } else { + OVSDB_TRACE(Trace, "Deleting port vlan binding port " + + physical_port_name_ + " vlan " + integerToString(vlan_)); + port->DeleteBinding(vlan_, NULL); + } + port->Encode(txn); +} + +void VlanPortBindingEntry::ChangeMsg(struct ovsdb_idl_txn *txn) { + PhysicalPortEntry *port = + static_cast(physical_port_.get()); + OVSDB_TRACE(Trace, "Deleting port vlan binding port " + + physical_port_name_ + " vlan " + integerToString(vlan_)); + port->DeleteBinding(vlan_, NULL); + + AddMsg(txn); +} + +void VlanPortBindingEntry::DeleteMsg(struct ovsdb_idl_txn *txn) { + if (!physical_port_) { + return; + } + PhysicalPortEntry *port = + static_cast(physical_port_.get()); + OVSDB_TRACE(Trace, "Deleting port vlan binding port " + + physical_port_name_ + " vlan " + integerToString(vlan_)); + port->DeleteBinding(vlan_, + static_cast(logical_switch_.get())); + port->Encode(txn); +} + +bool VlanPortBindingEntry::Sync(DBEntry *db_entry) { + AGENT::VlanLogicalPortEntry *entry = + static_cast(db_entry); + std::string ls_name; + boost::uuids::uuid vmi_uuid; + bool change = false; + + if (entry->vm_interface()) { + vmi_uuid = entry->vm_interface()->GetUuid(); + } + + if (entry->vm_interface() && entry->vm_interface()->vn()) { + ls_name = UuidToString(entry->vm_interface()->vn()->GetUuid()); + } + + if (vmi_uuid_ != vmi_uuid) { + vmi_uuid_ = vmi_uuid; + change = true; + } + + if (ls_name != logical_switch_name_) { + logical_switch_name_ = ls_name; + change = true; + } + + return change; +} + +bool VlanPortBindingEntry::IsLess(const KSyncEntry &entry) const { + const VlanPortBindingEntry &vps_entry = + static_cast(entry); + if (vlan_ != vps_entry.vlan_) + return vlan_ < vps_entry.vlan_; + if (physical_device_name_ != vps_entry.physical_device_name_) + return physical_device_name_ < vps_entry.physical_device_name_; + return physical_port_name_ < vps_entry.physical_port_name_; +} + +KSyncEntry *VlanPortBindingEntry::UnresolvedReference() { + PhysicalPortTable *p_table = table_->client_idl()->physical_port_table(); + PhysicalPortEntry key(p_table, physical_port_name_.c_str()); + PhysicalPortEntry *p_port = + static_cast(p_table->GetReference(&key)); + if (!p_port->IsResolved()) { + OVSDB_TRACE(Trace, "Physical Port unavailable for Port Vlan Binding " + + physical_port_name_ + " vlan " + integerToString(vlan_) + + " to Logical Switch " + logical_switch_name_); + return p_port; + } + + PhysicalSwitchTable *ps_table = + table_->client_idl()->physical_switch_table(); + PhysicalSwitchEntry ps_key(ps_table, physical_device_name_.c_str()); + PhysicalSwitchEntry *p_switch = + static_cast(ps_table->GetReference(&ps_key)); + if (!p_switch->IsResolved()) { + OVSDB_TRACE(Trace, "Physical Switch unavailable for Port Vlan Binding "+ + physical_port_name_ + " vlan " + integerToString(vlan_) + + " to Logical Switch " + logical_switch_name_); + return p_switch; + } + + VMInterfaceKSyncObject *vm_intf_table = + table_->client_idl()->vm_interface_table(); + VMInterfaceKSyncEntry vm_intf_key(vm_intf_table, vmi_uuid_); + VMInterfaceKSyncEntry *vm_intf = static_cast( + vm_intf_table->GetReference(&vm_intf_key)); + if (!vm_intf->IsResolved()) { + OVSDB_TRACE(Trace, "VM Interface unavailable for Port Vlan Binding " + + physical_port_name_ + " vlan " + integerToString(vlan_) + + " to Logical Switch " + logical_switch_name_); + return vm_intf; + } else if (logical_switch_name_.empty()) { + // update latest name after resolution. + logical_switch_name_ = vm_intf->vn_name(); + } + + if (!logical_switch_name_.empty()) { + // Check only if logical switch name is present. + LogicalSwitchTable *l_table = + table_->client_idl()->logical_switch_table(); + LogicalSwitchEntry ls_key(l_table, logical_switch_name_.c_str()); + LogicalSwitchEntry *ls_entry = + static_cast(l_table->GetReference(&ls_key)); + if (!ls_entry->IsResolved()) { + OVSDB_TRACE(Trace, "Logical Switch unavailable for Port Vlan " + "Binding " + physical_port_name_ + " vlan " + + integerToString(vlan_) + " to Logical Switch " + + logical_switch_name_); + return ls_entry; + } + } + + return NULL; +} + +const std::string &VlanPortBindingEntry::logical_switch_name() const { + return logical_switch_name_; +} + +const std::string &VlanPortBindingEntry::physical_port_name() const { + return physical_port_name_; +} + +const std::string &VlanPortBindingEntry::physical_device_name() const { + return physical_device_name_; +} + +uint16_t VlanPortBindingEntry::vlan() const { + return vlan_; +} + +VlanPortBindingTable::VlanPortBindingTable(OvsdbClientIdl *idl, DBTable *table) : + OvsdbDBObject(idl, table) { +} + +VlanPortBindingTable::~VlanPortBindingTable() { +} + +void VlanPortBindingTable::OvsdbNotify(OvsdbClientIdl::Op op, + struct ovsdb_idl_row *row) { +} + +KSyncEntry *VlanPortBindingTable::Alloc(const KSyncEntry *key, uint32_t index) { + const VlanPortBindingEntry *k_entry = + static_cast(key); + VlanPortBindingEntry *entry = new VlanPortBindingEntry(this, k_entry); + return entry; +} + +KSyncEntry *VlanPortBindingTable::DBToKSyncEntry(const DBEntry* db_entry) { + const AGENT::VlanLogicalPortEntry *entry = + static_cast(db_entry); + VlanPortBindingEntry *key = new VlanPortBindingEntry(this, entry); + return static_cast(key); +} + +OvsdbDBEntry *VlanPortBindingTable::AllocOvsEntry(struct ovsdb_idl_row *row) { + return NULL; +} + +KSyncDBObject::DBFilterResp VlanPortBindingTable::DBEntryFilter( + const DBEntry *entry) { + const AGENT::VlanLogicalPortEntry *l_port = + static_cast(entry); + // Since we need physical port name and device name as key, ignore entry + // if physical port or device is not yet present. + if (l_port->physical_port() == NULL) { + OVSDB_TRACE(Trace, "Ignoring Port Vlan Binding due to physical port " + "unavailablity Logical port = " + l_port->name()); + return DBFilterIgnore; // TODO(Prabhjot) check if Delete is required. + } + if (l_port->physical_port()->device() == NULL) { + OVSDB_TRACE(Trace, "Ignoring Port Vlan Binding due to device " + "unavailablity Logical port = " + l_port->name()); + return DBFilterIgnore; // TODO(Prabhjot) check if Delete is required. + } + return DBFilterAccept; +} + +///////////////////////////////////////////////////////////////////////////// +// Sandesh routines +///////////////////////////////////////////////////////////////////////////// +class VlanPortBindingSandeshTask : public Task { +public: + VlanPortBindingSandeshTask(std::string resp_ctx) : + Task((TaskScheduler::GetInstance()->GetTaskId("Agent::KSync")), -1), + resp_(new OvsdbVlanPortBindingResp()), resp_data_(resp_ctx) { + } + virtual ~VlanPortBindingSandeshTask() {} + virtual bool Run() { + std::vector bindings; + TorAgentInit *init = + static_cast(Agent::GetInstance()->agent_init()); + OvsdbClientSession *session = init->ovsdb_client()->next_session(NULL); + VlanPortBindingTable *table = + session->client_idl()->vlan_port_table(); + VlanPortBindingEntry *entry = + static_cast(table->Next(NULL)); + while (entry != NULL) { + OvsdbVlanPortBindingEntry oentry; + oentry.set_state(entry->StateString()); + oentry.set_physical_port(entry->physical_port_name()); + oentry.set_physical_device(entry->physical_device_name()); + oentry.set_logical_switch(entry->logical_switch_name()); + oentry.set_vlan(entry->vlan()); + bindings.push_back(oentry); + entry = static_cast(table->Next(entry)); + } + resp_->set_bindings(bindings); + SendResponse(); + return true; + } +private: + void SendResponse() { + resp_->set_context(resp_data_); + resp_->set_more(false); + resp_->Response(); + } + + OvsdbVlanPortBindingResp *resp_; + std::string resp_data_; + DISALLOW_COPY_AND_ASSIGN(VlanPortBindingSandeshTask); +}; + +void OvsdbVlanPortBindingReq::HandleRequest() const { + VlanPortBindingSandeshTask *task = new VlanPortBindingSandeshTask(context()); + TaskScheduler *scheduler = TaskScheduler::GetInstance(); + scheduler->Enqueue(task); +} + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/vlan_port_binding_ovsdb.h b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/vlan_port_binding_ovsdb.h new file mode 100644 index 00000000000..4eb9a33aa54 --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/vlan_port_binding_ovsdb.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +#ifndef SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_VLAN_PORT_BINDING_OVSDB_H_ +#define SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_VLAN_PORT_BINDING_OVSDB_H_ + +#include +#include + +namespace AGENT { +class PhysicalDeviceVnEntry; +class VlanLogicalPortEntry; +}; + +namespace OVSDB { +class VlanPortBindingTable : public OvsdbDBObject { +public: + VlanPortBindingTable(OvsdbClientIdl *idl, DBTable *table); + virtual ~VlanPortBindingTable(); + + void OvsdbNotify(OvsdbClientIdl::Op, struct ovsdb_idl_row*); + KSyncEntry *Alloc(const KSyncEntry *key, uint32_t index); + KSyncEntry *DBToKSyncEntry(const DBEntry*); + OvsdbDBEntry* AllocOvsEntry(struct ovsdb_idl_row*); + DBFilterResp DBEntryFilter(const DBEntry *entry); + +private: + DISALLOW_COPY_AND_ASSIGN(VlanPortBindingTable); +}; + +class VlanPortBindingEntry : public OvsdbDBEntry { +public: + VlanPortBindingEntry(VlanPortBindingTable *table, + const VlanPortBindingEntry *key); + VlanPortBindingEntry(VlanPortBindingTable *table, + const AGENT::VlanLogicalPortEntry *entry); + + void PreAddChange(); + void PostDelete(); + void AddMsg(struct ovsdb_idl_txn *); + void ChangeMsg(struct ovsdb_idl_txn *); + void DeleteMsg(struct ovsdb_idl_txn *); + bool Sync(DBEntry*); + bool IsLess(const KSyncEntry&) const; + std::string ToString() const {return "Vlan Port Binding";} + KSyncEntry* UnresolvedReference(); + + const std::string &logical_switch_name() const; + const std::string &physical_port_name() const; + const std::string &physical_device_name() const; + uint16_t vlan() const; + +private: + friend class VlanPortBindingTable; + KSyncEntryPtr logical_switch_; + KSyncEntryPtr physical_port_; + std::string logical_switch_name_; + std::string physical_port_name_; + std::string physical_device_name_; + uint16_t vlan_; + boost::uuids::uuid vmi_uuid_; + DISALLOW_COPY_AND_ASSIGN(VlanPortBindingEntry); +}; +}; + +#endif //SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_VLAN_PORT_BINDING_OVSDB_H_ + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/vm_interface_ksync.cc b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/vm_interface_ksync.cc new file mode 100644 index 00000000000..839989d6a65 --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/vm_interface_ksync.cc @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +extern "C" { +#include +}; +#include + +#include +#include +#include +#include + +using OVSDB::OvsdbDBEntry; +using OVSDB::VMInterfaceKSyncEntry; +using OVSDB::VMInterfaceKSyncObject; + +VMInterfaceKSyncEntry::VMInterfaceKSyncEntry(VMInterfaceKSyncObject *table, + const VmInterface *entry) : OvsdbDBEntry(table_), + uuid_(entry->GetUuid()) { +} + +VMInterfaceKSyncEntry::VMInterfaceKSyncEntry(VMInterfaceKSyncObject *table, + const VMInterfaceKSyncEntry *key) : OvsdbDBEntry(table), + uuid_(key->uuid_) { +} + +VMInterfaceKSyncEntry::VMInterfaceKSyncEntry(VMInterfaceKSyncObject *table, + boost::uuids::uuid uuid) : OvsdbDBEntry(table), uuid_(uuid) { +} + +void VMInterfaceKSyncEntry::AddMsg(struct ovsdb_idl_txn *txn) { +} + +void VMInterfaceKSyncEntry::ChangeMsg(struct ovsdb_idl_txn *txn) { +} + +void VMInterfaceKSyncEntry::DeleteMsg(struct ovsdb_idl_txn *txn) { +} + +bool VMInterfaceKSyncEntry::Sync(DBEntry *db_entry) { + VmInterface *entry = static_cast(db_entry); + + std::string vn_name; + if (entry->vn()) { + vn_name = UuidToString(entry->vn()->GetUuid()); + } + if (vn_name_ != vn_name) { + vn_name_ = vn_name; + return true; + } + return false; +} + +bool VMInterfaceKSyncEntry::IsLess(const KSyncEntry &entry) const { + const VMInterfaceKSyncEntry &intf_entry = + static_cast(entry); + return uuid_ < intf_entry.uuid_; +} + +KSyncEntry *VMInterfaceKSyncEntry::UnresolvedReference() { + if (vn_name_.empty()) { + return table_->client_idl()->ksync_obj_manager()->default_defer_entry(); + } + return NULL; +} + +const std::string &VMInterfaceKSyncEntry::vn_name() const { + return vn_name_; +} + +VMInterfaceKSyncObject::VMInterfaceKSyncObject(OvsdbClientIdl *idl, DBTable *table) : + OvsdbDBObject(idl, table) { +} + +VMInterfaceKSyncObject::~VMInterfaceKSyncObject() { +} + +void VMInterfaceKSyncObject::OvsdbNotify(OvsdbClientIdl::Op op, + struct ovsdb_idl_row *row) { +} + +KSyncEntry *VMInterfaceKSyncObject::Alloc(const KSyncEntry *key, uint32_t index) { + const VMInterfaceKSyncEntry *k_entry = + static_cast(key); + VMInterfaceKSyncEntry *entry = new VMInterfaceKSyncEntry(this, k_entry); + return entry; +} + +KSyncEntry *VMInterfaceKSyncObject::DBToKSyncEntry(const DBEntry* db_entry) { + const VmInterface *entry = static_cast(db_entry); + VMInterfaceKSyncEntry *key = new VMInterfaceKSyncEntry(this, entry); + return static_cast(key); +} + +OvsdbDBEntry *VMInterfaceKSyncObject::AllocOvsEntry(struct ovsdb_idl_row *row) { + return NULL; +} + +KSyncDBObject::DBFilterResp VMInterfaceKSyncObject::DBEntryFilter( + const DBEntry *entry) { + const Interface *intf = static_cast(entry); + // only accept vm interfaces + if (intf->type() != Interface::VM_INTERFACE) { + return DBFilterIgnore; + } + return DBFilterAccept; +} + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/vm_interface_ksync.h b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/vm_interface_ksync.h new file mode 100644 index 00000000000..005a459b38c --- /dev/null +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/ovsdb_client/vm_interface_ksync.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +#ifndef SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_VM_INTERFACE_KSYNC_H_ +#define SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_VM_INTERFACE_KSYNC_H_ + +#include +#include + +class VmInterface; + +namespace OVSDB { +class VMInterfaceKSyncObject : public OvsdbDBObject { +public: + VMInterfaceKSyncObject(OvsdbClientIdl *idl, DBTable *table); + virtual ~VMInterfaceKSyncObject(); + + void OvsdbNotify(OvsdbClientIdl::Op, struct ovsdb_idl_row*); + KSyncEntry *Alloc(const KSyncEntry *key, uint32_t index); + KSyncEntry *DBToKSyncEntry(const DBEntry*); + OvsdbDBEntry* AllocOvsEntry(struct ovsdb_idl_row*); + DBFilterResp DBEntryFilter(const DBEntry *entry); + +private: + DISALLOW_COPY_AND_ASSIGN(VMInterfaceKSyncObject); +}; + +class VMInterfaceKSyncEntry : public OvsdbDBEntry { +public: + VMInterfaceKSyncEntry(VMInterfaceKSyncObject *table, + const VMInterfaceKSyncEntry *key); + VMInterfaceKSyncEntry(VMInterfaceKSyncObject *table, + const VmInterface *entry); + VMInterfaceKSyncEntry(VMInterfaceKSyncObject *table, + boost::uuids::uuid uuid); + + bool IsDataResolved() {return true;}; + void AddMsg(struct ovsdb_idl_txn *); + void ChangeMsg(struct ovsdb_idl_txn *); + void DeleteMsg(struct ovsdb_idl_txn *); + bool Sync(DBEntry*); + bool IsLess(const KSyncEntry&) const; + std::string ToString() const {return "VM Interface Ksync";} + KSyncEntry* UnresolvedReference(); + + const std::string &vn_name() const; + +private: + friend class VMInterfaceKSyncObject; + boost::uuids::uuid uuid_; + std::string vn_name_; + DISALLOW_COPY_AND_ASSIGN(VMInterfaceKSyncEntry); +}; +}; + +#endif //SRC_VNSW_AGENT_PHYSICAL_DEVICES_OVS_TOR_AGENT_OVSDB_CLIENT_VM_INTERFACE_KSYNC_H_ + diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/tor_agent_init.cc b/src/vnsw/agent/physical_devices/ovs_tor_agent/tor_agent_init.cc index f9bb251d26a..25155f0628e 100644 --- a/src/vnsw/agent/physical_devices/ovs_tor_agent/tor_agent_init.cc +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/tor_agent_init.cc @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -29,12 +30,14 @@ #include #include -#include +#include +#include #include using std::string; using std::cout; +using OVSDB::OvsdbClient; TorAgentInit::TorAgentInit() { } @@ -63,21 +66,21 @@ string TorAgentInit::ModuleName() { return "TorAgent-" + InstanceId(); } -string TorAgentInit::AgentName() { - TorAgentParam *param = dynamic_cast(agent_param()); - return param->host_name() + "-" + InstanceId(); -} - void TorAgentInit::FactoryInit() { } void TorAgentInit::CreatePeers() { - ovs_peer_manager_.reset(new OvsPeerManager()); + ovs_peer_manager_.reset(new OvsPeerManager(agent())); } void TorAgentInit::CreateModules() { device_manager_.reset(new PhysicalDeviceManager(agent())); agent()->set_device_manager(device_manager_.get()); + ovsdb_client_.reset(OvsdbClient::Allocate(agent(), + static_cast(agent_param()), + ovs_peer_manager())); + uve_.reset(new AgentUveBase(agent(), AgentUveBase::kBandwidthInterval)); + agent()->set_uve(uve_.get()); } void TorAgentInit::CreateDBTables() { @@ -86,10 +89,13 @@ void TorAgentInit::CreateDBTables() { void TorAgentInit::RegisterDBClients() { device_manager_->RegisterDBClients(); + ovsdb_client_->RegisterClients(); + uve_->RegisterDBClients(); } void TorAgentInit::InitModules() { device_manager_->Init(); + uve_->Init(); } void TorAgentInit::ConnectToController() { @@ -99,6 +105,10 @@ void TorAgentInit::ConnectToController() { /**************************************************************************** * Shutdown routines ****************************************************************************/ +void TorAgentInit::UveShutdown() { + uve_->Shutdown(); +} + void TorAgentInit::WaitForIdle() { sleep(5); } diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/tor_agent_init.h b/src/vnsw/agent/physical_devices/ovs_tor_agent/tor_agent_init.h index f2b5da8a0b6..6f4fe1ca914 100644 --- a/src/vnsw/agent/physical_devices/ovs_tor_agent/tor_agent_init.h +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/tor_agent_init.h @@ -14,6 +14,9 @@ class Agent; class AgentParam; class PhysicalDeviceManager; class OvsPeerManager; +namespace OVSDB { +class OvsdbClient; +}; // The class to drive agent initialization. // Defines control parameters used to enable/disable agent features @@ -28,7 +31,6 @@ class TorAgentInit : public AgentInit { virtual std::string InstanceId(); virtual std::string ModuleName(); - virtual std::string AgentName(); // Initialization virtual methods void FactoryInit(); void CreatePeers(); @@ -39,15 +41,19 @@ class TorAgentInit : public AgentInit { void ConnectToController(); // Shutdown virtual methods + void UveShutdown(); void WaitForIdle(); // Accessor methods PhysicalDeviceManager *device_manager() const; OvsPeerManager *ovs_peer_manager() const; + OVSDB::OvsdbClient *ovsdb_client() {return ovsdb_client_.get();} private: std::auto_ptr device_manager_; std::auto_ptr ovs_peer_manager_; + std::auto_ptr ovsdb_client_; + std::auto_ptr uve_; DISALLOW_COPY_AND_ASSIGN(TorAgentInit); }; diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/tor_agent_param.cc b/src/vnsw/agent/physical_devices/ovs_tor_agent/tor_agent_param.cc index 8492ccc13d6..58ae336c0bd 100644 --- a/src/vnsw/agent/physical_devices/ovs_tor_agent/tor_agent_param.cc +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/tor_agent_param.cc @@ -27,6 +27,8 @@ void TorAgentParam::AddOptions() { tor.add_options() ("TOR.tor_ip", boost_po::value()->default_value(""), "IP Address of the ToR being managed") + ("TOR.tsn_ip", boost_po::value()->default_value(""), + "IP Address of the ToR Service Node") ("TOR.tor_id", boost_po::value()->default_value(""), "Identifier of the TOR"); AgentParam::AddOptions(tor); @@ -39,6 +41,7 @@ void TorAgentParam::InitFromConfig() { // Parse ToR specific arguments ParseIp("TOR.tor_ip", &tor_info_.ip_); + ParseIp("TOR.tsn_ip", &tor_info_.tsn_ip_); GetValueFromTree(tor_info_.id_, "TOR.tor_id"); GetValueFromTree(tor_info_.type_, "TOR.tor_type"); GetValueFromTree(tor_info_.protocol_, "TOR.tor_ovs_protocol"); @@ -53,6 +56,7 @@ void TorAgentParam::InitFromArguments() { boost::program_options::variables_map vars = var_map(); ParseIpArgument(vars, tor_info_.ip_, "TOR.tor_ip"); + ParseIpArgument(vars, tor_info_.tsn_ip_, "TOR.tsn_ip"); GetOptValue(vars, tor_info_.id_, "TOR.tor_id"); GetOptValue(vars, tor_info_.type_, "TOR.tor_type"); GetOptValue(vars, tor_info_.protocol_, "TOR.tor_ovs_protocol"); @@ -65,6 +69,11 @@ int TorAgentParam::Validate() { return (EINVAL); } + if (tor_info_.tsn_ip_ == Ip4Address::from_string("0.0.0.0")) { + LOG(ERROR, "Configuration error. TSN IP address not specified"); + return (EINVAL); + } + if (tor_info_.id_ == "") { LOG(ERROR, "Configuration error. ToR ID not specified"); return (EINVAL); diff --git a/src/vnsw/agent/physical_devices/ovs_tor_agent/tor_agent_param.h b/src/vnsw/agent/physical_devices/ovs_tor_agent/tor_agent_param.h index abd9914e67b..9735abdee60 100644 --- a/src/vnsw/agent/physical_devices/ovs_tor_agent/tor_agent_param.h +++ b/src/vnsw/agent/physical_devices/ovs_tor_agent/tor_agent_param.h @@ -20,6 +20,7 @@ class TorAgentParam : public AgentParam { struct TorInfo { std::string type_; Ip4Address ip_; + Ip4Address tsn_ip_; std::string id_; // Protocol to connect to ToR std::string protocol_; @@ -33,6 +34,10 @@ class TorAgentParam : public AgentParam { void AddOptions(); std::string tor_id() const { return tor_info_.id_; } + std::string tor_protocol() const { return tor_info_.protocol_; } + Ip4Address tor_ip() const { return tor_info_.ip_; } + Ip4Address tsn_ip() const { return tor_info_.tsn_ip_; } + int tor_port() const { return tor_info_.port_; } private: virtual void InitFromConfig(); diff --git a/src/vnsw/agent/physical_devices/tables/device_manager.cc b/src/vnsw/agent/physical_devices/tables/device_manager.cc index f9e8018fbb6..2885efff140 100644 --- a/src/vnsw/agent/physical_devices/tables/device_manager.cc +++ b/src/vnsw/agent/physical_devices/tables/device_manager.cc @@ -14,6 +14,7 @@ #include #include #include +#include using boost::assign::map_list_of; using boost::assign::list_of; @@ -61,24 +62,31 @@ void PhysicalDeviceManager::RegisterDBClients() { IFMapDependencyManager *mgr = agent_->oper_db()->dependency_manager(); ReactionMap device_react = map_list_of - ("virtual-network", list_of("self")) - ("self", list_of("self")); + ("self", list_of("self")) + ("physical-router-physical-interface", list_of("self")); mgr->RegisterReactionMap("physical-router", device_react); ReactionMap physical_port_react = map_list_of - ("physical-router", list_of("self")) - ("self", list_of("self")); + ("self", list_of("self") ("physical-router-physical-interface")) + ("physical-interface-logical-interface", + list_of("physical-router-physical-interface")); mgr->RegisterReactionMap("physical-interface", physical_port_react); ReactionMap logical_port_react = map_list_of - ("physical-interface", list_of("self")) - ("self", list_of("self")); + ("self", list_of("physical-interface-logical-interface")) + ("physical-interface-logical-interface", + list_of("physical-router-physical-interface")) + ("logical-interface-virtual-machine-interface", + list_of("physical-interface-logical-interface")); mgr->RegisterReactionMap("logical-interface", logical_port_react); device_table_->RegisterDBClients(mgr); physical_port_table_->RegisterDBClients(mgr); logical_port_table_->RegisterDBClients(mgr); physical_device_vn_table_->RegisterDBClients(mgr); + if (agent_->tsn_enabled()) { + tsn_vrf_listener_.reset(new TsnVrfListener(agent())); + } } void PhysicalDeviceManager::Init() { diff --git a/src/vnsw/agent/physical_devices/tables/device_manager.h b/src/vnsw/agent/physical_devices/tables/device_manager.h index 93fc0401f04..0b1112009ab 100644 --- a/src/vnsw/agent/physical_devices/tables/device_manager.h +++ b/src/vnsw/agent/physical_devices/tables/device_manager.h @@ -14,6 +14,7 @@ class PhysicalPortTable; class LogicalPortTable; class PhysicalDeviceVnTable; } +class TsnVrfListener; class PhysicalDeviceManager { public: @@ -43,6 +44,7 @@ class PhysicalDeviceManager { AGENT::PhysicalPortTable *physical_port_table_; AGENT::LogicalPortTable *logical_port_table_; AGENT::PhysicalDeviceVnTable *physical_device_vn_table_; + std::auto_ptr tsn_vrf_listener_; DISALLOW_COPY_AND_ASSIGN(PhysicalDeviceManager); }; diff --git a/src/vnsw/agent/physical_devices/tables/logical_port.cc b/src/vnsw/agent/physical_devices/tables/logical_port.cc index eb861e5de21..3f3d5624ae9 100644 --- a/src/vnsw/agent/physical_devices/tables/logical_port.cc +++ b/src/vnsw/agent/physical_devices/tables/logical_port.cc @@ -58,6 +58,11 @@ bool LogicalPortEntry::CopyBase(LogicalPortTable *table, const LogicalPortData *data) { bool ret = false; + if (fq_name_ != data->fq_name_) { + fq_name_ = data->fq_name_; + ret = true; + } + if (name_ != data->name_) { name_ = data->name_; ret = true; @@ -148,13 +153,13 @@ static LogicalPortKey *BuildKey(const autogen::LogicalInterface *port) { autogen::IdPermsType id_perms = port->id_perms(); boost::uuids::uuid u; CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong, u); - return new DefaultLogicalPortKey(u); + return new VlanLogicalPortKey(u); } static LogicalPortData *BuildData(const Agent *agent, IFMapNode *node, const autogen::LogicalInterface *port) { // Find link with physical-interface adjacency - boost::uuids::uuid physical_port_uuid; + boost::uuids::uuid physical_port_uuid = nil_uuid(); IFMapNode *adj_node = NULL; adj_node = agent->cfg_listener()->FindAdjacentIFMapNode (agent, node, "physical-interface"); @@ -167,7 +172,7 @@ static LogicalPortData *BuildData(const Agent *agent, IFMapNode *node, } // Find link with virtual-machine-interface adjacency - boost::uuids::uuid vmi_uuid; + boost::uuids::uuid vmi_uuid = nil_uuid(); adj_node = agent->cfg_listener()->FindAdjacentIFMapNode (agent, node, "virtual-machine-interface"); if (adj_node) { @@ -179,7 +184,11 @@ static LogicalPortData *BuildData(const Agent *agent, IFMapNode *node, vmi_uuid); } - return new LogicalPortData(node->name(), physical_port_uuid, vmi_uuid); + return new AGENT::VlanLogicalPortData(node->name(), + port->display_name(), + physical_port_uuid, + vmi_uuid, + port->vlan_tag()); } bool LogicalPortTable::IFNodeToReq(IFMapNode *node, DBRequest &req) { @@ -216,15 +225,26 @@ class LogicalPortSandesh : public AgentSandesh { } }; +void LogicalPortEntry::SetSandeshData(SandeshLogicalPort *data) const { +} + static void SetLogicalPortSandeshData(const LogicalPortEntry *entry, SandeshLogicalPort *data) { data->set_uuid(UuidToString(entry->uuid())); + data->set_fq_name(entry->fq_name()); data->set_name(entry->name()); if (entry->physical_port()) { data->set_physical_port(entry->physical_port()->name()); } else { data->set_physical_port("INVALID"); } + + if (entry->vm_interface()) { + data->set_vif(entry->vm_interface()->name()); + } else { + data->set_vif("INVALID"); + } + entry->SetSandeshData(data); } bool LogicalPortEntry::DBEntrySandesh(Sandesh *resp, std::string &name) const { @@ -270,6 +290,7 @@ void LogicalPortEntry::SendObjectLog(AgentLogEvent::type event) const { info.set_event(str); info.set_uuid(UuidToString(uuid_)); + info.set_fq_name(fq_name_); info.set_name(name_); if (physical_port_) { info.set_physical_port(physical_port_->name()); @@ -308,6 +329,10 @@ bool VlanLogicalPortEntry::Copy(LogicalPortTable *table, return ret; } +void VlanLogicalPortEntry::SetSandeshData(SandeshLogicalPort *data) const { + data->set_vlan_tag(vlan_); +} + ////////////////////////////////////////////////////////////////////////////// // DefaultLogicalPort routines ////////////////////////////////////////////////////////////////////////////// diff --git a/src/vnsw/agent/physical_devices/tables/logical_port.h b/src/vnsw/agent/physical_devices/tables/logical_port.h index 0e091d0ce66..bcf08b51729 100644 --- a/src/vnsw/agent/physical_devices/tables/logical_port.h +++ b/src/vnsw/agent/physical_devices/tables/logical_port.h @@ -11,6 +11,7 @@ class IFMapDependencyManager; class VmInterface; +class SandeshLogicalPort; namespace AGENT { struct LogicalPortKey; @@ -24,7 +25,7 @@ class LogicalPortEntry : AgentRefCount, public AgentDBEntry { }; explicit LogicalPortEntry(const boost::uuids::uuid &id) : - uuid_(id), name_(), physical_port_(), vm_interface_() { } + uuid_(id), fq_name_(), physical_port_(), vm_interface_() { } virtual ~LogicalPortEntry() { } virtual bool IsLess(const DBEntry &rhs) const; @@ -35,6 +36,7 @@ class LogicalPortEntry : AgentRefCount, public AgentDBEntry { } const boost::uuids::uuid &uuid() const { return uuid_; } + const std::string &fq_name() const { return fq_name_; } const std::string &name() const { return name_; } PhysicalPortEntry *physical_port() const { return physical_port_.get(); } VmInterface *vm_interface() const; @@ -42,12 +44,14 @@ class LogicalPortEntry : AgentRefCount, public AgentDBEntry { bool CopyBase(LogicalPortTable *table, const LogicalPortData *data); virtual bool Copy(LogicalPortTable *table, const LogicalPortData *data) = 0; + virtual void SetSandeshData(SandeshLogicalPort *data) const; void SendObjectLog(AgentLogEvent::type event) const; bool DBEntrySandesh(Sandesh *sresp, std::string &name) const; private: friend class LogicalPortTable; boost::uuids::uuid uuid_; + std::string fq_name_; std::string name_; PhysicalPortEntryRef physical_port_; InterfaceRef vm_interface_; @@ -94,11 +98,14 @@ struct LogicalPortKey : public AgentKey { }; struct LogicalPortData : public AgentData { - LogicalPortData(const std::string &name, const boost::uuids::uuid &port, + LogicalPortData(const std::string &fq_name, const std::string &name, + const boost::uuids::uuid &port, const boost::uuids::uuid &vif) : - name_(name), physical_port_(port), vm_interface_(vif) { } + fq_name_(fq_name), name_(name), physical_port_(port), + vm_interface_(vif) { } virtual ~LogicalPortData() { } + std::string fq_name_; std::string name_; boost::uuids::uuid physical_port_; boost::uuids::uuid vm_interface_; @@ -113,9 +120,10 @@ struct VlanLogicalPortKey : public LogicalPortKey { }; struct VlanLogicalPortData : public LogicalPortData { - VlanLogicalPortData(const std::string &name, const boost::uuids::uuid &port, + VlanLogicalPortData(const std::string &fq_name, const std::string &name, + const boost::uuids::uuid &port, const boost::uuids::uuid &vif, uint16_t vlan) : - LogicalPortData(name, port, vif), vlan_(vlan) { } + LogicalPortData(fq_name, name, port, vif), vlan_(vlan) { } virtual ~VlanLogicalPortData() { } uint16_t vlan_; @@ -130,6 +138,7 @@ class VlanLogicalPortEntry : public LogicalPortEntry { uint16_t vlan() const { return vlan_; } bool Copy(LogicalPortTable *table, const LogicalPortData *data); + void SetSandeshData(SandeshLogicalPort *data) const; private: uint16_t vlan_; @@ -145,10 +154,10 @@ struct DefaultLogicalPortKey : public LogicalPortKey { }; struct DefaultLogicalPortData : public LogicalPortData { - DefaultLogicalPortData(const std::string &name, + DefaultLogicalPortData(const std::string &fq_name, const std::string &name, const boost::uuids::uuid &port, const boost::uuids::uuid &vif) : - LogicalPortData(name, port, vif) { } + LogicalPortData(fq_name, name, port, vif) { } virtual ~DefaultLogicalPortData() { } }; diff --git a/src/vnsw/agent/physical_devices/tables/physical_device.cc b/src/vnsw/agent/physical_devices/tables/physical_device.cc index 9254c4608ae..d2f8b0c209b 100644 --- a/src/vnsw/agent/physical_devices/tables/physical_device.cc +++ b/src/vnsw/agent/physical_devices/tables/physical_device.cc @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -69,9 +70,15 @@ void PhysicalDeviceEntry::SetKey(const DBRequestKey *key) { uuid_ = k->uuid_; } -bool PhysicalDeviceEntry::Copy(const PhysicalDeviceData *data) { +bool PhysicalDeviceEntry::Copy(const PhysicalDeviceTable *table, + const PhysicalDeviceData *data) { bool ret = false; + if (fq_name_ != data->fq_name_) { + fq_name_ = data->fq_name_; + ret = true; + } + if (name_ != data->name_) { name_ = data->name_; ret = true; @@ -92,12 +99,25 @@ bool PhysicalDeviceEntry::Copy(const PhysicalDeviceData *data) { ret = true; } + if (management_ip_ != data->management_ip_) { + management_ip_ = data->management_ip_; + ret = true; + } + ManagementProtocol proto = FromString(data->protocol_); if (protocol_ != proto) { protocol_ = proto; ret = true; } + if (ifmap_node_ != data->ifmap_node_) { + OperDB *oper = table->agent()->oper_db(); + oper->dependency_manager()->SetObject(data->ifmap_node_, this); + if (ifmap_node_) + oper->dependency_manager()->ResetObject(ifmap_node_); + ifmap_node_ = data->ifmap_node_; + } + return ret; } @@ -116,7 +136,7 @@ DBEntry *PhysicalDeviceTable::Add(const DBRequest *req) { PhysicalDeviceData *data = static_cast (req->data.get()); PhysicalDeviceEntry *dev = new PhysicalDeviceEntry(key->uuid_); - dev->Copy(data); + dev->Copy(this, data); dev->SendObjectLog(AgentLogEvent::ADD); return dev; } @@ -125,7 +145,7 @@ bool PhysicalDeviceTable::OnChange(DBEntry *entry, const DBRequest *req) { PhysicalDeviceEntry *dev = static_cast(entry); PhysicalDeviceData *data = static_cast (req->data.get()); - bool ret = dev->Copy(data); + bool ret = dev->Copy(this, data); dev->SendObjectLog(AgentLogEvent::CHANGE); return ret; } @@ -133,6 +153,8 @@ bool PhysicalDeviceTable::OnChange(DBEntry *entry, const DBRequest *req) { bool PhysicalDeviceTable::Delete(DBEntry *entry, const DBRequest *req) { PhysicalDeviceEntry *dev = static_cast(entry); dev->SendObjectLog(AgentLogEvent::DELETE); + if (dev->ifmap_node_) + agent()->oper_db()->dependency_manager()->ResetObject(dev->ifmap_node_); return true; } @@ -151,6 +173,11 @@ DBTableBase *PhysicalDeviceTable::CreateTable(DB *db, const std::string &name) { // Config handling ///////////////////////////////////////////////////////////////////////////// void PhysicalDeviceTable::ConfigEventHandler(DBEntry *entry) { + PhysicalDeviceEntry *dev = static_cast(entry); + DBRequest req; + if (IFNodeToReq(dev->ifmap_node_, req) == true) { + Enqueue(&req); + } } void PhysicalDeviceTable::RegisterDBClients(IFMapDependencyManager *dep) { @@ -168,14 +195,15 @@ static PhysicalDeviceKey *BuildKey(const autogen::PhysicalRouter *router) { return new PhysicalDeviceKey(u); } -static PhysicalDeviceData *BuildData(const IFMapNode *node, +static PhysicalDeviceData *BuildData(IFMapNode *node, const autogen::PhysicalRouter *router) { boost::system::error_code ec; - IpAddress ip = IpAddress::from_string(router->dataplane_ip(), ec); - IpAddress mip = IpAddress::from_string(router->management_ip(), ec); - assert(!ec); - return new PhysicalDeviceData(node->name(), router->vendor_name(), - ip, mip, "ovs"); + IpAddress ip = IpAddress(); + IpAddress mip = IpAddress(); + ip = IpAddress::from_string(router->dataplane_ip(), ec); + mip = IpAddress::from_string(router->management_ip(), ec); + return new PhysicalDeviceData(node->name(), router->display_name(), + router->vendor_name(), ip, mip, "OVS", node); } bool PhysicalDeviceTable::IFNodeToReq(IFMapNode *node, DBRequest &req) { @@ -186,6 +214,7 @@ bool PhysicalDeviceTable::IFNodeToReq(IFMapNode *node, DBRequest &req) { req.key.reset(BuildKey(router)); if (node->IsDeleted()) { req.oper = DBRequest::DB_ENTRY_DELETE; + agent()->device_manager()->physical_device_vn_table()->ConfigUpdate(node); return true; } @@ -221,6 +250,7 @@ class DeviceSandesh : public AgentSandesh { static void SetDeviceSandeshData(const PhysicalDeviceEntry *entry, SandeshDevice *data) { data->set_uuid(UuidToString(entry->uuid())); + data->set_fq_name(entry->fq_name()); data->set_name(entry->name()); data->set_vendor(entry->vendor()); data->set_ip_address(entry->ip().to_string()); @@ -272,6 +302,7 @@ void PhysicalDeviceEntry::SendObjectLog(AgentLogEvent::type event) const { info.set_event(str); info.set_uuid(UuidToString(uuid_)); + info.set_fq_name(fq_name_); info.set_name(name_); info.set_vendor(vendor_); info.set_ip_address(ip_.to_string()); diff --git a/src/vnsw/agent/physical_devices/tables/physical_device.h b/src/vnsw/agent/physical_devices/tables/physical_device.h index d149357df52..ce160ecf5cb 100644 --- a/src/vnsw/agent/physical_devices/tables/physical_device.h +++ b/src/vnsw/agent/physical_devices/tables/physical_device.h @@ -19,18 +19,22 @@ struct PhysicalDeviceKey : public AgentKey { }; struct PhysicalDeviceData : public AgentData { - PhysicalDeviceData(const std::string &name, const std::string &vendor, - const IpAddress &ip, const IpAddress &mgmt_ip, - const std::string &protocol) : - AgentData(), name_(name), vendor_(vendor), ip_(ip), - management_ip_(mgmt_ip), protocol_(protocol) { } + PhysicalDeviceData(const std::string &fq_name, const std::string &name, + const std::string &vendor, + const IpAddress &ip, const IpAddress &mgmt_ip, + const std::string &protocol, IFMapNode *ifmap_node) : + AgentData(), fq_name_(fq_name), name_(name), vendor_(vendor), ip_(ip), + management_ip_(mgmt_ip), protocol_(protocol), ifmap_node_(ifmap_node) { + } virtual ~PhysicalDeviceData() { } + std::string fq_name_; std::string name_; std::string vendor_; IpAddress ip_; IpAddress management_ip_; std::string protocol_; + IFMapNode *ifmap_node_; }; class PhysicalDeviceEntry : AgentRefCount, @@ -42,7 +46,8 @@ class PhysicalDeviceEntry : AgentRefCount, } ManagementProtocol; explicit PhysicalDeviceEntry(const boost::uuids::uuid &id) : - uuid_(id), name_(""), vendor_(""), ip_(), protocol_(INVALID) { } + uuid_(id), name_(""), vendor_(""), ip_(), protocol_(INVALID), + ifmap_node_(NULL) { } virtual ~PhysicalDeviceEntry() { } virtual bool IsLess(const DBEntry &rhs) const; @@ -53,8 +58,9 @@ class PhysicalDeviceEntry : AgentRefCount, return AgentRefCount::GetRefCount(); } - bool Copy(const PhysicalDeviceData *data); + bool Copy(const PhysicalDeviceTable *table, const PhysicalDeviceData *data); const boost::uuids::uuid &uuid() const { return uuid_; } + const std::string &fq_name() const { return fq_name_; } const std::string &name() const { return name_; } const std::string &vendor() const { return vendor_; } const IpAddress &ip() const { return ip_; } @@ -67,11 +73,13 @@ class PhysicalDeviceEntry : AgentRefCount, private: friend class PhysicalDeviceTable; boost::uuids::uuid uuid_; + std::string fq_name_; std::string name_; std::string vendor_; IpAddress ip_; IpAddress management_ip_; ManagementProtocol protocol_; + IFMapNode *ifmap_node_; DISALLOW_COPY_AND_ASSIGN(PhysicalDeviceEntry); }; diff --git a/src/vnsw/agent/physical_devices/tables/physical_device_vn.cc b/src/vnsw/agent/physical_devices/tables/physical_device_vn.cc index 3c992b64cfe..41b90361ead 100644 --- a/src/vnsw/agent/physical_devices/tables/physical_device_vn.cc +++ b/src/vnsw/agent/physical_devices/tables/physical_device_vn.cc @@ -130,16 +130,60 @@ void PhysicalDeviceVnTable::RegisterDBClients(IFMapDependencyManager *dep) { // Config handling routines ////////////////////////////////////////////////////////////////////////////// /* - * There is no IFMapNode for PhysicalDeviceVnEntry. The entries are built from - * link between physical-router and virtual-network. + * There is no IFMapNode for PhysicalDeviceVnEntry. We act on physical-router + * notification to build the PhysicalDeviceVnTable. * - * We act on physical-router notification to build the PhysicalDeviceVnTable. - * From a physical-router run thru all the links to find the virtual-networks. + * From a physical-router run iterate thru the links given below, + * - - - + * - * - * We dont get notification of link deletion between physical-router and - * virtual-network. Instead, we build a config-tree and audit the tree based - * on version-number to identify deleted entries + * Since there is no node for physical-device-vn, we build a config-tree and + * audit the tree based on version-number to identify deleted entries */ +void PhysicalDeviceVnTable::IterateConfig(const Agent *agent, const char *type, + IFMapNode *node, AgentKey *key, + AgentData *data, + const boost::uuids::uuid &dev_uuid) { + CfgListener *cfg = agent->cfg_listener(); + if (strcmp(type, "physical-interface") == 0) { + cfg->ForEachAdjacentIFMapNode + (agent, node, "logical-interface", NULL, NULL, + boost::bind(&PhysicalDeviceVnTable::IterateConfig, this, _1, _2, + _3, _4, _5, dev_uuid)); + return; + } + + if (strcmp(type, "logical-interface") != 0) { + return; + } + + IFMapNode *adj_node = NULL; + adj_node = cfg->FindAdjacentIFMapNode(agent, node, + "virtual-machine-interface"); + if (adj_node == NULL) + return; + + adj_node = cfg->FindAdjacentIFMapNode(agent, adj_node, "virtual-network"); + if (adj_node == NULL) + return; + + autogen::VirtualNetwork *vn = static_cast + (adj_node->GetObject()); + assert(vn); + autogen::IdPermsType id_perms = vn->id_perms(); + boost::uuids::uuid vn_uuid; + CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong, + vn_uuid); + + PhysicalDeviceVnKey vn_key(dev_uuid, vn_uuid); + config_tree_[vn_key] = config_version_; + DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE); + req.key.reset(new PhysicalDeviceVnKey(dev_uuid, vn_uuid)); + req.data.reset(new PhysicalDeviceVnData()); + Enqueue(&req); + return; +} + void PhysicalDeviceVnTable::ConfigUpdate(IFMapNode *node) { config_version_++; @@ -147,45 +191,27 @@ void PhysicalDeviceVnTable::ConfigUpdate(IFMapNode *node) { (node->GetObject()); assert(router); autogen::IdPermsType id_perms = router->id_perms(); - boost::uuids::uuid router_uuid; + boost::uuids::uuid router_uuid = nil_uuid(); CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong, router_uuid); - // Go thru virtual-networks linked and add/update them in the config tree - IFMapAgentTable *table = static_cast(node->table()); - for (DBGraphVertex::adjacency_iterator iter = - node->begin(table->GetGraph()); - iter != node->end(table->GetGraph()); ++iter) { - IFMapNode *adj_node = static_cast(iter.operator->()); - if (agent()->cfg_listener()->SkipNode(adj_node)) { - continue; - } - - if (strcmp(adj_node->table()->Typename(), "virtual-network") != 0) { - continue; - } - autogen::VirtualNetwork *vn = static_cast - (adj_node->GetObject()); - assert(vn); - autogen::IdPermsType id_perms = vn->id_perms(); - boost::uuids::uuid vn_uuid; - CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong, - vn_uuid); - - PhysicalDeviceVnKey key(router_uuid, vn_uuid); - if (config_tree_.find(key) == config_tree_.end()) { - DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE); - req.key.reset(new PhysicalDeviceVnKey(router_uuid, vn_uuid)); - req.data.reset(new PhysicalDeviceVnData()); - Enqueue(&req); - } - config_tree_[key] = config_version_; + if (!node->IsDeleted()) { + agent()->cfg_listener()->ForEachAdjacentIFMapNode + (agent(), node, "physical-interface", NULL, NULL, + boost::bind(&PhysicalDeviceVnTable::IterateConfig, this, _1, _2, + _3, _4, _5, router_uuid)); } // Audit and delete entries with old version-number in config-tree ConfigIterator it = config_tree_.begin(); while (it != config_tree_.end()){ ConfigIterator del_it = it++; + if (del_it->first.device_uuid_ != router_uuid) { + // update version number and skip entry if it belongs to different + // physical router/device + del_it->second = config_version_; + continue; + } if (del_it->second < config_version_) { DBRequest req(DBRequest::DB_ENTRY_DELETE); req.key.reset(new PhysicalDeviceVnKey(del_it->first.device_uuid_, diff --git a/src/vnsw/agent/physical_devices/tables/physical_device_vn.h b/src/vnsw/agent/physical_devices/tables/physical_device_vn.h index 74961ee65ea..9abe819b0ba 100644 --- a/src/vnsw/agent/physical_devices/tables/physical_device_vn.h +++ b/src/vnsw/agent/physical_devices/tables/physical_device_vn.h @@ -98,6 +98,9 @@ class PhysicalDeviceVnTable : public AgentDBTable { virtual bool Delete(DBEntry *entry, const DBRequest *req); virtual bool IFNodeToReq(IFMapNode *node, DBRequest &req); + void IterateConfig(const Agent *agent, const char *type, IFMapNode *node, + AgentKey *key, AgentData *data, + const boost::uuids::uuid &dev_uuid); PhysicalDeviceTable *physical_device_table() const { return physical_device_table_; } diff --git a/src/vnsw/agent/physical_devices/tables/physical_devices.sandesh b/src/vnsw/agent/physical_devices/tables/physical_devices.sandesh index 9fdcd7eea25..aa1822e11e4 100644 --- a/src/vnsw/agent/physical_devices/tables/physical_devices.sandesh +++ b/src/vnsw/agent/physical_devices/tables/physical_devices.sandesh @@ -7,10 +7,11 @@ ****************************************************************************/ struct SandeshDevice { 1: string uuid; - 2: string name; - 3: string vendor; - 4: string ip_address; - 5: string management_protocol; + 2: string fq_name; + 3: string name; + 4: string vendor; + 5: string ip_address; + 6: string management_protocol; } response sandesh SandeshDeviceListResp { @@ -25,10 +26,11 @@ struct DeviceObjectLogInfo { 1: string event; 2: string uuid; 3: i32 ref_count; - 4: string name; - 5: string vendor; - 6: string ip_address; - 7: string management_protocol; + 4: string fq_name; + 5: string name; + 6: string vendor; + 7: string ip_address; + 8: string management_protocol; } objectlog sandesh DeviceObjectLog { @@ -42,8 +44,9 @@ struct PhysicalPortObjectLogInfo { 1: string event; 2: string uuid; 3: i32 ref_count; - 4: string name; - 5: string device; + 4: string fq_name; + 5: string name; + 6: string device; } objectlog sandesh PhysicalPortObjectLog { @@ -52,8 +55,9 @@ objectlog sandesh PhysicalPortObjectLog { struct SandeshPhysicalPort { 1: string uuid; - 2: string name; - 3: string device; + 2: string fq_name; + 3: string name; + 4: string device; } response sandesh SandeshPhysicalPortListResp { @@ -70,8 +74,11 @@ request sandesh SandeshPhysicalPortReq { ****************************************************************************/ struct SandeshLogicalPort { 1: string uuid; - 2: string name; - 3: string physical_port; + 2: string fq_name; + 3: string name; + 4: string physical_port; + 5: string vif; + 6: u16 vlan_tag; } response sandesh SandeshLogicalPortListResp { @@ -87,8 +94,11 @@ struct LogicalPortObjectLogInfo { 1: string event; 2: string uuid; 3: i32 ref_count; - 4: string name; - 5: string physical_port; + 4: string fq_name; + 5: string name; + 6: string physical_port; + 7: string vif; + 8: u16 vlan_tag; } objectlog sandesh LogicalPortObjectLog { diff --git a/src/vnsw/agent/physical_devices/tables/physical_port.cc b/src/vnsw/agent/physical_devices/tables/physical_port.cc index 73d93cf4c97..1a50238cebc 100644 --- a/src/vnsw/agent/physical_devices/tables/physical_port.cc +++ b/src/vnsw/agent/physical_devices/tables/physical_port.cc @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -53,6 +54,11 @@ bool PhysicalPortEntry::Copy(PhysicalPortTable *table, const PhysicalPortData *data) { bool ret = false; + if (fq_name_ != data->fq_name_) { + fq_name_ = data->fq_name_; + ret = true; + } + if (name_ != data->name_) { name_ = data->name_; ret = true; @@ -62,6 +68,15 @@ bool PhysicalPortEntry::Copy(PhysicalPortTable *table, if (dev != device_.get()) { device_.reset(dev); ret = true; + + if (device_ && device_->name() == table->agent()->host_name()) { + //Create a physical interface + InterfaceTable *intf_table = table->agent()->interface_table(); + PhysicalInterface::Create(intf_table, name_, + table->agent()->fabric_vrf_name(), + PhysicalInterface::FABRIC, + PhysicalInterface::ETHERNET, false); + } } return ret; @@ -135,7 +150,7 @@ static PhysicalPortKey *BuildKey(const autogen::PhysicalInterface *port) { static PhysicalPortData *BuildData(const Agent *agent, IFMapNode *node, const autogen::PhysicalInterface *port) { - boost::uuids::uuid dev_uuid; + boost::uuids::uuid dev_uuid = nil_uuid(); // Find link with physical-router adjacency IFMapNode *adj_node = NULL; adj_node = agent->cfg_listener()->FindAdjacentIFMapNode(agent, node, @@ -148,7 +163,7 @@ static PhysicalPortData *BuildData(const Agent *agent, IFMapNode *node, dev_uuid); } - return new PhysicalPortData(node->name(), dev_uuid); + return new PhysicalPortData(node->name(), port->display_name(), dev_uuid); } bool PhysicalPortTable::IFNodeToReq(IFMapNode *node, DBRequest &req) { @@ -188,6 +203,7 @@ class AgentPhysicalPortSandesh : public AgentSandesh { static void SetPhysicalPortSandeshData(const PhysicalPortEntry *entry, SandeshPhysicalPort *data) { data->set_uuid(UuidToString(entry->uuid())); + data->set_fq_name(entry->fq_name()); data->set_name(entry->name()); if (entry->device()) { data->set_device(entry->device()->name()); @@ -240,6 +256,7 @@ void PhysicalPortEntry::SendObjectLog(AgentLogEvent::type event) const { info.set_event(str); info.set_uuid(UuidToString(uuid_)); + info.set_fq_name(fq_name_); info.set_name(name_); if (device_) { info.set_device(device_->name()); diff --git a/src/vnsw/agent/physical_devices/tables/physical_port.h b/src/vnsw/agent/physical_devices/tables/physical_port.h index 7a2da872609..68366364576 100644 --- a/src/vnsw/agent/physical_devices/tables/physical_port.h +++ b/src/vnsw/agent/physical_devices/tables/physical_port.h @@ -20,10 +20,12 @@ struct PhysicalPortKey : public AgentKey { }; struct PhysicalPortData : public AgentData { - PhysicalPortData(const std::string &name, const boost::uuids::uuid &dev) : - name_(name), device_(dev) { } + PhysicalPortData(const std::string fq_name, const std::string &name, + const boost::uuids::uuid &dev) : + fq_name_(fq_name), name_(name), device_(dev) { } virtual ~PhysicalPortData() { } + std::string fq_name_; std::string name_; boost::uuids::uuid device_; }; @@ -43,6 +45,7 @@ class PhysicalPortEntry : AgentRefCount, public AgentDBEntry{ } const boost::uuids::uuid &uuid() const { return uuid_; } + const std::string &fq_name() const { return fq_name_; } const std::string &name() const { return name_; } PhysicalDeviceEntry *device() const { return device_.get(); } @@ -54,6 +57,7 @@ class PhysicalPortEntry : AgentRefCount, public AgentDBEntry{ private: friend class PhysicalPortTable; boost::uuids::uuid uuid_; + std::string fq_name_; std::string name_; PhysicalDeviceEntryRef device_; DISALLOW_COPY_AND_ASSIGN(PhysicalPortEntry); diff --git a/src/vnsw/agent/physical_devices/test/physical-device-vn.xml b/src/vnsw/agent/physical_devices/test/physical-device-vn.xml index 260f51864c8..cb41baae097 100644 --- a/src/vnsw/agent/physical_devices/test/physical-device-vn.xml +++ b/src/vnsw/agent/physical_devices/test/physical-device-vn.xml @@ -1,31 +1,70 @@ - - + + + + + + - + right="physical-interface" right-name="intf-1"/> + present="no" /> - - - + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + diff --git a/src/vnsw/agent/physical_devices/tsn/SConscript b/src/vnsw/agent/physical_devices/tsn/SConscript new file mode 100644 index 00000000000..da40bb9356f --- /dev/null +++ b/src/vnsw/agent/physical_devices/tsn/SConscript @@ -0,0 +1,13 @@ +# +# Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. +# + +# -*- mode: python; -*- + +import sys +Import('AgentEnv') +env = AgentEnv.Clone() + +tsn = env.Library('tsn', + ['tsn_vrf_listener.cc', + ]) diff --git a/src/vnsw/agent/physical_devices/tsn/tsn_vrf_listener.cc b/src/vnsw/agent/physical_devices/tsn/tsn_vrf_listener.cc new file mode 100644 index 00000000000..abacb885fd1 --- /dev/null +++ b/src/vnsw/agent/physical_devices/tsn/tsn_vrf_listener.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +TsnVrfListener::TsnVrfListener(Agent *agent) : agent_(agent) { + vrf_table_listener_id_ = agent->vrf_table()->Register( + boost::bind(&TsnVrfListener::VrfNotify, this, _2)); +} + +TsnVrfListener::~TsnVrfListener() { + agent_->vrf_table()->Unregister(vrf_table_listener_id_); +} + +void TsnVrfListener::VrfNotify(DBEntryBase *entry) { + VrfEntry *vrf = static_cast(entry); + if (vrf->GetName() == agent_->fabric_vrf_name()) + return; + MacAddress address(agent_->vhost_interface()->mac()); + + if (entry->IsDeleted()) { + Layer2AgentRouteTable::Delete(agent_->local_peer(), vrf->GetName(), -1, + address); + return; + } + + if (vrf->vn()) { + Layer2AgentRouteTable::AddLayer2ReceiveRoute(agent_->local_peer(), + vrf->GetName(), + vrf->vn()->GetName(), + address, + "pkt0", true); + } +} diff --git a/src/vnsw/agent/physical_devices/tsn/tsn_vrf_listener.h b/src/vnsw/agent/physical_devices/tsn/tsn_vrf_listener.h new file mode 100644 index 00000000000..cf110abe2a3 --- /dev/null +++ b/src/vnsw/agent/physical_devices/tsn/tsn_vrf_listener.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. + */ + +#ifndef tsn_vrf_listener_h_ +#define tsn_vrf_listener_h_ + +class TsnVrfListener { +public: + TsnVrfListener(Agent *agent); + virtual ~TsnVrfListener(); + void VrfNotify(DBEntryBase *entry); + +private: + Agent *agent_; + DBTableBase::ListenerId vrf_table_listener_id_; + DISALLOW_COPY_AND_ASSIGN(TsnVrfListener); +}; + +#endif // tsn_vrf_listener_h_ diff --git a/src/vnsw/agent/pkt/flow_handler.cc b/src/vnsw/agent/pkt/flow_handler.cc index 7c590553c40..cb16df0de72 100644 --- a/src/vnsw/agent/pkt/flow_handler.cc +++ b/src/vnsw/agent/pkt/flow_handler.cc @@ -49,6 +49,7 @@ bool FlowHandler::Run() { pkt_info_->sport = fe->key().src_port; pkt_info_->dport = fe->key().dst_port; pkt_info_->tcp_ack = fe->is_flags_set(FlowEntry::TcpAckFlow); + pkt_info_->vrf = fe->data().vrf; } if (info.Process(pkt_info_.get(), &in, &out) == false) { diff --git a/src/vnsw/agent/pkt/pkt_flow_info.cc b/src/vnsw/agent/pkt/pkt_flow_info.cc index 1943a2b499c..71ee66d938b 100644 --- a/src/vnsw/agent/pkt/pkt_flow_info.cc +++ b/src/vnsw/agent/pkt/pkt_flow_info.cc @@ -201,6 +201,12 @@ static bool NhDecode(const NextHop *nh, const PktInfo *pkt, PktFlowInfo *info, break; } + case NextHop::VRF: { + const VrfNH *vrf_nh = static_cast(nh); + out->vrf_ = vrf_nh->GetVrf(); + break; + } + case NextHop::TUNNEL: { if (pkt->family == Address::INET) { const InetUnicastRouteEntry *rt = @@ -223,6 +229,28 @@ static bool NhDecode(const NextHop *nh, const PktInfo *pkt, PktFlowInfo *info, break; } + case NextHop::ARP: { + const ArpNH *arp_nh = static_cast(nh); + if (in->intf_->type() == Interface::VM_INTERFACE) { + const VmInterface *vm_intf = + static_cast(in->intf_); + if (vm_intf->sub_type() == VmInterface::VCPE) { + out->nh_ = arp_nh->id(); + } else { + out->nh_ = arp_nh->GetInterface()->flow_key_nh()->id(); + } + } + out->intf_ = arp_nh->GetInterface(); + break; + } + + case NextHop::RESOLVE: { + const ResolveNH *rsl_nh = static_cast(nh); + out->nh_ = rsl_nh->interface()->flow_key_nh()->id(); + out->intf_ = rsl_nh->interface(); + break; + } + default: out->intf_ = NULL; break; @@ -277,7 +305,7 @@ static const VnEntry *InterfaceToVn(const Interface *intf) { } static bool IntfHasFloatingIp(const Interface *intf, Address::Family family) { - if (intf->type() != Interface::VM_INTERFACE) + if (!intf || intf->type() != Interface::VM_INTERFACE) return NULL; return static_cast(intf)->HasFloatingIp(family); } @@ -508,6 +536,9 @@ void PktFlowInfo::LinkLocalServiceFromVm(const PktInfo *pkt, PktControlInfo *in, // the packet not coming to vrouter for reverse NAT. // Destination would be local host (FindLinkLocalService returns this) nat_ip_saddr = vm_port->mdata_ip_addr(); + // Services such as metadata will run on compute_node_ip. Set nat + // address to compute_node_ip + nat_server = Agent::GetInstance()->compute_node_ip(); nat_sport = pkt->sport; } else { nat_ip_saddr = Agent::GetInstance()->router_id(); @@ -549,8 +580,8 @@ void PktFlowInfo::LinkLocalServiceFromHost(const PktInfo *pkt, PktControlInfo *i return; } - if ((pkt->ip_daddr.to_v4().to_ulong() != vm_port->mdata_ip_addr().to_ulong()) || - (pkt->ip_saddr.to_v4().to_ulong() != Agent::GetInstance()->router_id().to_ulong())) { + // Check if packet is destined to metadata of interface + if (pkt->ip_daddr.to_v4() != vm_port->mdata_ip_addr()) { // Force implicit deny in->rt_ = NULL; out->rt_ = NULL; @@ -900,7 +931,6 @@ void PktFlowInfo::IngressProcess(const PktInfo *pkt, PktControlInfo *in, if (out->intf_ == NULL && out->rt_) { RouteToOutInfo(out->rt_, pkt, this, in, out); } - if (out->rt_) { const NextHop* nh = out->rt_->GetActiveNextHop(); if (nh && nh->GetType() == NextHop::TUNNEL) { @@ -934,6 +964,7 @@ void PktFlowInfo::EgressProcess(const PktInfo *pkt, PktControlInfo *in, UpdateRoute(&out->rt_, out->vrf_,pkt->ip_daddr, flow_dest_plen_map); UpdateRoute(&in->rt_, out->vrf_,pkt->ip_saddr, flow_source_plen_map); + if (out->intf_) { out->vn_ = InterfaceToVn(out->intf_); } @@ -949,6 +980,21 @@ void PktFlowInfo::EgressProcess(const PktInfo *pkt, PktControlInfo *in, } } + if (out->rt_) { + if (out->rt_->GetActiveNextHop()->GetType() == NextHop::ARP || + out->rt_->GetActiveNextHop()->GetType() == NextHop::RESOLVE) { + //If a packet came with mpls label pointing to + //vrf NH, then we need to do a route lookup + //and set the nexthop for reverse flow properly + //as mpls pointed NH would not be used for reverse flow + if (RouteToOutInfo(out->rt_, pkt, this, in, out)) { + if (out->intf_) { + out->vn_ = InterfaceToVn(out->intf_); + } + } + } + } + return; } @@ -1011,7 +1057,6 @@ bool PktFlowInfo::Process(const PktInfo *pkt, PktControlInfo *in, short_flow_reason = FlowEntry::SHORT_NO_DST_ROUTE; return false; } - flow_source_vrf = static_cast(in->rt_)->vrf_id(); flow_dest_vrf = out->rt_->vrf_id(); diff --git a/src/vnsw/agent/pkt/pkt_handler.cc b/src/vnsw/agent/pkt/pkt_handler.cc index aab1478d9d6..8c132b88e53 100644 --- a/src/vnsw/agent/pkt/pkt_handler.cc +++ b/src/vnsw/agent/pkt/pkt_handler.cc @@ -39,7 +39,8 @@ const std::size_t PktTrace::kPktMaxTraceSize; //////////////////////////////////////////////////////////////////////////////// PktHandler::PktHandler(Agent *agent, PktModule *pkt_module) : - stats_(), agent_(agent), pkt_module_(pkt_module) { + stats_(), iid_(DBTableBase::kInvalidId), agent_(agent), + pkt_module_(pkt_module) { for (int i = 0; i < MAX_MODULES; ++i) { if (i == PktHandler::DHCP || i == PktHandler::DHCPV6 || i == PktHandler::DNS) @@ -52,6 +53,60 @@ PktHandler::PktHandler(Agent *agent, PktModule *pkt_module) : PktHandler::~PktHandler() { } +void PktHandler::RegisterDBClients() { + iid_ = agent_->interface_table()->Register( + boost::bind(&PktHandler::InterfaceNotify, this, _2)); +} + +void PktHandler::Shutdown() { + if (iid_ != DBTableBase::kInvalidId) { + agent_->interface_table()->Unregister(iid_); + iid_ = DBTableBase::kInvalidId; + } +} + +void PktHandler::InterfaceNotify(DBEntryBase *entry) { + Interface *itf = static_cast(entry); + if (itf->type() != Interface::VM_INTERFACE) + return; + + const VmInterface *vmitf = static_cast(entry); + if (vmitf->vm_mac().empty()) + return; + + boost::system::error_code ec; + MacAddress address(vmitf->vm_mac(), &ec); + if (ec) { + return; + } + + MacVmBindingSet::iterator it = FindMacVmBinding(address, itf); + if (it != mac_vm_binding_.end()) + mac_vm_binding_.erase(it); + + if (!entry->IsDeleted()) { + if (!vmitf->vn() || vmitf->vn()->GetVxLanId() == 0) { + return; + } + // assumed that VM mac does not change + MacVmBindingKey key(address, vmitf->vn()->GetVxLanId(), itf); + mac_vm_binding_.insert(key); + } +} + +PktHandler::MacVmBindingSet::iterator +PktHandler::FindMacVmBinding(MacAddress &address, const Interface *interface) { + MacVmBindingSet::iterator it = + mac_vm_binding_.lower_bound(MacVmBindingKey(address, 0, NULL)); + while (it != mac_vm_binding_.end()) { + if (it->interface == interface) + return it; + it++; + } + + return it; +} + void PktHandler::Register(PktModuleName type, RcvQueueFunc cb) { enqueue_cb_.at(type) = cb; } @@ -81,24 +136,19 @@ void PktHandler::HandleRcvPkt(const AgentHdr &hdr, const PacketBufferPtr &buff){ pkt_info->agent_hdr = hdr; agent_->stats()->incr_pkt_exceptions(); - intf = agent_->interface_table()->FindInterface(hdr.ifindex); - if (intf == NULL) { - PKT_TRACE(Err, "Invalid interface index <" << hdr.ifindex << ">"); - agent_->stats()->incr_pkt_invalid_interface(); - goto enqueue; + if (!IsValidInterface(hdr.ifindex, &intf)) { + goto drop; } - if (intf->type() == Interface::VM_INTERFACE) { - VmInterface *vm_itf = static_cast(intf); - if (!vm_itf->layer3_forwarding()) { - PKT_TRACE(Err, "ipv4 not enabled for interface index <" << - hdr.ifindex << ">"); - agent_->stats()->incr_pkt_dropped(); + ParseUserPkt(pkt_info.get(), intf, pkt_type, pkt); + if (pkt_info->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) { + // In case of a control packet from a TOR served by us, the ifindex + // is modified to index of the VM interface; validate this interface. + if (!IsValidInterface(pkt_info->agent_hdr.ifindex, &intf)) { goto drop; } } - ParseUserPkt(pkt_info.get(), intf, pkt_type, pkt); pkt_info->vrf = pkt_info->agent_hdr.vrf; // Handle ARP packet @@ -202,6 +252,24 @@ static bool InterestedIPv6Protocol(uint8_t proto) { return false; } + +uint8_t *PktHandler::ParseEthernetHeader(PktInfo *pkt_info, + PktType::Type &pkt_type, + uint8_t *pkt) { + pkt_info->eth = (struct ether_header *) pkt; + pkt_info->ether_type = ntohs(pkt_info->eth->ether_type); + + if (pkt_info->ether_type == ETHERTYPE_VLAN) { + pkt = ((uint8_t *)pkt_info->eth) + sizeof(struct ether_header) + 4; + uint16_t *tmp = ((uint16_t *)pkt) - 1; + pkt_info->ether_type = ntohs(*tmp); + } else { + pkt = ((uint8_t *)pkt_info->eth) + sizeof(struct ether_header); + } + + return pkt; +} + uint8_t *PktHandler::ParseIpPacket(PktInfo *pkt_info, PktType::Type &pkt_type, uint8_t *pkt) { if (pkt_info->ether_type == ETHERTYPE_IP) { @@ -345,16 +413,7 @@ int PktHandler::ParseMPLSoUDP(PktInfo *pkt_info, uint8_t *pkt) { uint8_t *PktHandler::ParseUserPkt(PktInfo *pkt_info, Interface *intf, PktType::Type &pkt_type, uint8_t *pkt) { // get to the actual packet header - pkt_info->eth = (struct ether_header *) pkt; - pkt_info->ether_type = ntohs(pkt_info->eth->ether_type); - - if (pkt_info->ether_type == ETHERTYPE_VLAN) { - pkt = ((uint8_t *)pkt_info->eth) + sizeof(struct ether_header) + 4; - uint16_t *tmp = ((uint16_t *)pkt) - 1; - pkt_info->ether_type = ntohs(*tmp); - } else { - pkt = ((uint8_t *)pkt_info->eth) + sizeof(struct ether_header); - } + pkt = ParseEthernetHeader(pkt_info, pkt_type, pkt); // Parse payload if (pkt_info->ether_type == ETHERTYPE_ARP) { @@ -374,6 +433,12 @@ uint8_t *PktHandler::ParseUserPkt(PktInfo *pkt_info, Interface *intf, SetOuterIp(pkt_info, pkt); // IP Packets pkt = ParseIpPacket(pkt_info, pkt_type, pkt); + + // If it is a packet from TOR that we serve, dont parse any further + if (IsManagedTORPacket(intf, pkt_info, pkt_type, pkt)) { + return pkt; + } + // If tunneling is not enabled on interface or if it is a DHCP packet, // dont parse any further if (intf->IsTunnelEnabled() == false || IsDHCPPacket(pkt_info)) { @@ -468,6 +533,60 @@ bool PktHandler::IsDHCPPacket(PktInfo *pkt_info) { return false; } +// We can receive DHCP / DNS packets on physical port from TOR ports managed +// by a TOR services node. Check if the source mac is the mac address of a +// VM interface available in the node. +bool PktHandler::IsManagedTORPacket(Interface *intf, PktInfo *pkt_info, + PktType::Type &pkt_type, uint8_t *pkt) { + if (intf->type() == Interface::PHYSICAL) { + if (pkt_type != PktType::UDP || pkt_info->dport != VXLAN_UDP_DEST_PORT) + return false; + + // Get VXLAN id and point to original L2 frame after the VXLAN header + uint32_t vxlan = ntohl(*(uint32_t *)(pkt + 4)) >> 8; + pkt += 8; + + // get to the actual packet header + pkt = ParseEthernetHeader(pkt_info, pkt_type, pkt); + + ether_addr addr; + memcpy(addr.ether_addr_octet, pkt_info->eth->ether_shost, ETH_ALEN); + MacAddress address(addr); + MacVmBindingKey key(address, vxlan, NULL); + MacVmBindingSet::iterator it = mac_vm_binding_.find(key); + if (it == mac_vm_binding_.end()) + return false; + + // update agent_hdr to reflect the VM interface data + // cmd_param is set to physical interface id + pkt_info->agent_hdr.cmd = AgentHdr::TRAP_TOR_CONTROL_PKT; + pkt_info->agent_hdr.cmd_param = pkt_info->agent_hdr.ifindex; + pkt_info->agent_hdr.ifindex = it->interface->id(); + pkt_info->agent_hdr.vrf = it->interface->vrf_id(); + + // Parse payload + if (pkt_info->ether_type == ETHERTYPE_ARP) { + pkt_info->arp = (ether_arp *) pkt; + pkt_type = PktType::ARP; + return true; + } + + // Identify NON-IP Packets + if (pkt_info->ether_type != ETHERTYPE_IP && + pkt_info->ether_type != ETHERTYPE_IPV6) { + pkt_info->data = pkt; + pkt_type = PktType::NON_IP; + return true; + } + + // IP Packets + pkt = ParseIpPacket(pkt_info, pkt_type, pkt); + return true; + } + + return false; +} + // Check if the packet is destined to the VM's default GW bool PktHandler::IsGwPacket(const Interface *intf, const IpAddress &dst_ip) { if (!intf || intf->type() != Interface::VM_INTERFACE) @@ -488,14 +607,16 @@ bool PktHandler::IsGwPacket(const Interface *intf, const IpAddress &dst_ip) { } if (IsIp4SubnetMember(vm_intf->ip_addr(), ipam[i].ip_prefix.to_v4(), ipam[i].plen)) - return (ipam[i].default_gw == dst_ip); + return (ipam[i].default_gw == dst_ip || + ipam[i].dns_server == dst_ip); } else { if (!ipam[i].IsV6()) { continue; } if (IsIp6SubnetMember(vm_intf->ip6_addr(), ipam[i].ip_prefix.to_v6(), ipam[i].plen)) - return (ipam[i].default_gw == dst_ip); + return (ipam[i].default_gw == dst_ip || + ipam[i].dns_server == dst_ip); } } @@ -504,6 +625,27 @@ bool PktHandler::IsGwPacket(const Interface *intf, const IpAddress &dst_ip) { return false; } +bool PktHandler::IsValidInterface(uint16_t ifindex, Interface **interface) { + Interface *intf = agent_->interface_table()->FindInterface(ifindex); + if (intf == NULL) { + PKT_TRACE(Err, "Invalid interface index <" << ifindex << ">"); + agent_->stats()->incr_pkt_invalid_interface(); + return false; + } + + if (intf->type() == Interface::VM_INTERFACE) { + VmInterface *vm_itf = static_cast(intf); + if (!vm_itf->layer3_forwarding()) { + PKT_TRACE(Err, "layer3 not enabled for interface index <" << + ifindex << ">"); + return false; + } + } + + *interface = intf; + return true; +} + void PktHandler::PktTraceIterate(PktModuleName mod, PktTraceCallback cb) { if (cb) { PktTrace &pkt(pkt_trace_.at(mod)); diff --git a/src/vnsw/agent/pkt/pkt_handler.h b/src/vnsw/agent/pkt/pkt_handler.h index abcc3e04f1a..b0f159db57b 100644 --- a/src/vnsw/agent/pkt/pkt_handler.h +++ b/src/vnsw/agent/pkt/pkt_handler.h @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -28,6 +29,7 @@ #define DHCPV6_SERVER_PORT 547 #define DHCPV6_CLIENT_PORT 546 #define DNS_SERVER_PORT 53 +#define VXLAN_UDP_DEST_PORT 4789 #define IPv4_ALEN 4 #define ARP_TX_BUFF_LEN 128 @@ -90,6 +92,7 @@ struct AgentHdr { TRAP_ECMP_RESOLVE = AGENT_TRAP_ECMP_RESOLVE, TRAP_SOURCE_MISMATCH = AGENT_TRAP_SOURCE_MISMATCH, TRAP_HANDLE_DF = AGENT_TRAP_HANDLE_DF, + TRAP_TOR_CONTROL_PKT = AGENT_TRAP_TOR_CONTROL_PKT, INVALID = MAX_AGENT_HDR_COMMANDS }; @@ -223,6 +226,8 @@ class PktHandler { PktHandler(Agent *, PktModule *pkt_module); virtual ~PktHandler(); + void RegisterDBClients(); + void Shutdown(); void Register(PktModuleName type, RcvQueueFunc cb); @@ -254,6 +259,25 @@ class PktHandler { private: friend bool ::CallPktParse(PktInfo *pkt_info, uint8_t *ptr, int len); + struct MacVmBindingKey { + MacAddress mac; + int vxlan; + InterfaceConstRef interface; + + MacVmBindingKey(MacAddress &m, int v, InterfaceConstRef intf) : + mac(m), vxlan(v), interface(intf) {} + bool operator<(const MacVmBindingKey &rhs) const { + if (mac != rhs.mac) + return mac < rhs.mac; + + return vxlan < rhs.vxlan; + } + }; + typedef std::set MacVmBindingSet; + + void InterfaceNotify(DBEntryBase *entry); + uint8_t *ParseEthernetHeader(PktInfo *pkt_info, + PktType::Type &pkt_type, uint8_t *pkt); uint8_t *ParseIpPacket(PktInfo *pkt_info, PktType::Type &pkt_type, uint8_t *ptr); uint8_t *ParseUserPkt(PktInfo *pkt_info, Interface *intf, @@ -262,6 +286,11 @@ class PktHandler { int ParseMPLSoGRE(PktInfo *pkt_info, uint8_t *pkt); int ParseMPLSoUDP(PktInfo *pkt_info, uint8_t *pkt); bool IsDHCPPacket(PktInfo *pkt_info); + bool IsValidInterface(uint16_t ifindex, Interface **interface); + bool IsManagedTORPacket(Interface *intf, PktInfo *pkt_info, + PktType::Type &pkt_type, uint8_t *pkt); + MacVmBindingSet::iterator + FindMacVmBinding(MacAddress &address, const Interface *interface); // handlers for each module type boost::array enqueue_cb_; @@ -269,6 +298,11 @@ class PktHandler { PktStats stats_; boost::array pkt_trace_; + // map of VM mac addresses to VM Interface, used in TOR services node + // to identify the VM based on incoming packet's mac address. + MacVmBindingSet mac_vm_binding_; + DBTableBase::ListenerId iid_; + Agent *agent_; PktModule *pkt_module_; diff --git a/src/vnsw/agent/pkt/pkt_init.cc b/src/vnsw/agent/pkt/pkt_init.cc index 478bc9086dc..1bc4957e378 100644 --- a/src/vnsw/agent/pkt/pkt_init.cc +++ b/src/vnsw/agent/pkt/pkt_init.cc @@ -29,6 +29,7 @@ void PktModule::Init(bool run_with_vrouter) { boost::asio::io_service &io = *agent_->event_manager()->io_service(); pkt_handler_.reset(new PktHandler(agent_, this)); + pkt_handler_->RegisterDBClients(); if (control_interface_) { control_interface_->Init(pkt_handler_.get()); @@ -50,6 +51,8 @@ void PktModule::set_control_interface(ControlInterface *intf) { } void PktModule::Shutdown() { + pkt_handler_->Shutdown(); + flow_proto_->Shutdown(); flow_proto_.reset(NULL); diff --git a/src/vnsw/agent/pkt/test/test_flowtable.cc b/src/vnsw/agent/pkt/test/test_flowtable.cc index 58621ea78db..78e67c7e730 100644 --- a/src/vnsw/agent/pkt/test/test_flowtable.cc +++ b/src/vnsw/agent/pkt/test/test_flowtable.cc @@ -490,7 +490,8 @@ int main(int argc, char *argv[]) { PhysicalInterface::CreateReq(Agent::GetInstance()->interface_table(), FlowTableTest::eth_itf, Agent::GetInstance()->fabric_vrf_name(), - PhysicalInterface::FABRIC); + PhysicalInterface::FABRIC, + PhysicalInterface::ETHERNET, false); client->WaitForIdle(); } diff --git a/src/vnsw/agent/pkt/test/test_pkt.cc b/src/vnsw/agent/pkt/test/test_pkt.cc index 26bf5180b09..8c97388feae 100644 --- a/src/vnsw/agent/pkt/test/test_pkt.cc +++ b/src/vnsw/agent/pkt/test/test_pkt.cc @@ -150,7 +150,8 @@ TEST_F(PktTest, FlowAdd_1) { PhysicalInterface::CreateReq(Agent::GetInstance()->interface_table(), "vnet0", Agent::GetInstance()->fabric_vrf_name(), - PhysicalInterface::FABRIC); + PhysicalInterface::FABRIC, + PhysicalInterface::ETHERNET, false); client->WaitForIdle(); TxMplsPacket(2, "1.1.1.2", "10.1.1.1", 0, "2.2.2.2", "3.3.3.3", 1); @@ -220,10 +221,10 @@ TEST_F(PktTest, tx_vlan_1) { DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE); req.key.reset(new VmInterfaceKey(AgentKey::ADD_DEL_CHANGE, MakeUuid(2), "vm-itf-2")); - req.data.reset(new VmInterfaceAddData(Ip4Address::from_string("1.1.1.2"), - "00:00:00:00:00:01", - "vm-1", MakeUuid(1), 1, 2, "vnet0", - Ip6Address())); + req.data.reset(new VmInterfaceConfigData + (Ip4Address::from_string("1.1.1.2"), "00:00:00:00:00:01", + "vm-1", MakeUuid(1), 1, 2, "vnet0", Ip6Address(), + VmInterface::EXTERNAL)); agent_->interface_table()->Enqueue(&req); client->WaitForIdle(); diff --git a/src/vnsw/agent/pkt/test/test_pkt_fip.cc b/src/vnsw/agent/pkt/test/test_pkt_fip.cc index e0ebb3bf3b9..56802026585 100644 --- a/src/vnsw/agent/pkt/test/test_pkt_fip.cc +++ b/src/vnsw/agent/pkt/test/test_pkt_fip.cc @@ -15,18 +15,20 @@ void RouterIdDepInit(Agent *agent) { } class FlowTest : public ::testing::Test { +public: virtual void SetUp() { + agent_ = Agent::GetInstance(); client->WaitForIdle(); - WAIT_FOR(1000, 100, - (0U == Agent::GetInstance()->pkt()->flow_table()->Size())); + WAIT_FOR(1000, 100, (0U == agent_->pkt()->flow_table()->Size())); } virtual void TearDown() { client->EnqueueFlowFlush(); client->WaitForIdle(); - WAIT_FOR(1000, 100, - (0U == Agent::GetInstance()->pkt()->flow_table()->Size())); + WAIT_FOR(1000, 100, (0U == agent_->pkt()->flow_table()->Size())); } + + Agent *agent_; }; struct PortInfo input1[] = { @@ -531,9 +533,8 @@ TEST_F(FlowTest, ServerToVm_1) { TxIpPacketUtil(vhost->id(), vhost_addr, "80.80.80.80", 1, 1); client->WaitForIdle(); EXPECT_TRUE(FlowGet(vhost->vrf()->GetName(), vhost_addr, "80.80.80.80", - 1, 0, 0, false, Agent::GetInstance()->fabric_vrf_name().c_str(), - // 1, 0, 0, false, Agent::GetInstance()->fabric_vn_name().c_str(), - Agent::GetInstance()->fabric_vn_name().c_str(), 1, + 1, 0, 0, false, agent_->fabric_vn_name().c_str(), + agent_->fabric_vn_name().c_str(), 1, true, false, vhost->flow_key_nh()->id())); EXPECT_TRUE(FlowDelete(vhost->vrf()->GetName(), vhost_addr, "80.80.80.80", @@ -552,7 +553,7 @@ TEST_F(FlowTest, ServerToVm_1) { vnet[1]->mdata_ip_addr().to_string().c_str(), 1, 0, 0, 1, "vrf1", "169.254.169.254", vnet_addr[1], 0, 0, - Agent::GetInstance()->fabric_vrf_name().c_str(), "vn1", + agent_->fabric_vn_name().c_str(), "vn1", vhost->flow_key_nh()->id(), vnet[1]->flow_key_nh()->id())); @@ -565,7 +566,7 @@ TEST_F(FlowTest, ServerToVm_1) { vnet[1]->mdata_ip_addr().to_string().c_str(), IPPROTO_UDP, 10, 20, 1, "vrf1", "169.254.169.254", vnet_addr[1], 10, 20, - Agent::GetInstance()->fabric_vrf_name().c_str(), "vn1", + agent_->fabric_vn_name().c_str(), "vn1", vhost->flow_key_nh()->id(), vnet[1]->flow_key_nh()->id())); @@ -578,14 +579,76 @@ TEST_F(FlowTest, ServerToVm_1) { vnet[1]->mdata_ip_addr().to_string().c_str(), IPPROTO_TCP, 10, 20, 1, "vrf1", "169.254.169.254", vnet_addr[1], 10, 20, - Agent::GetInstance()->fabric_vrf_name().c_str(), "vn1", + agent_->fabric_vn_name().c_str(), "vn1", vhost->flow_key_nh()->id(), vnet[1]->flow_key_nh()->id())); - // Agent::GetInstance()->fabric_vn_name().c_str(), "vn1")); RemoveMetadataService(); client->WaitForIdle(); } +// Test for traffic from server to VM. Source-IP different than vhost +TEST_F(FlowTest, ServerToVm_2) { + SetupMetadataService(); + client->WaitForIdle(); + char src_ip[32] = "80.80.80.1"; + + // Packet with no route for IP-DA + TxIpPacketUtil(vhost->id(), src_ip, "80.80.80.80", 1, 1); + client->WaitForIdle(); + EXPECT_TRUE(FlowGet(vhost->vrf()->GetName(), src_ip, "80.80.80.80", + 1, 0, 0, false, agent_->fabric_vn_name().c_str(), + agent_->fabric_vn_name().c_str(), 1, + true, false, vhost->flow_key_nh()->id())); + + EXPECT_TRUE(FlowDelete(vhost->vrf()->GetName(), src_ip, "80.80.80.80", + 1, 0, 0, vhost->flow_key_nh()->id())); + + client->WaitForIdle(); + EXPECT_TRUE(FlowFail(vhost->vrf()->GetName(), src_ip, "80.80.80.80", + 1, 0, 0, vhost->flow_key_nh()->id())); + + // Ping from server to vnet1 + TxIpPacketUtil(vhost->id(), src_ip, + vnet[1]->mdata_ip_addr().to_string().c_str(), 1, 1); + + EXPECT_TRUE(NatValidateFlow(1, vhost->vrf()->GetName().c_str(), + src_ip, + vnet[1]->mdata_ip_addr().to_string().c_str(), + 1, 0, 0, 1, "vrf1", "169.254.169.254", + vnet_addr[1], 0, 0, + agent_->fabric_vn_name().c_str(), "vn1", + vhost->flow_key_nh()->id(), + vnet[1]->flow_key_nh()->id())); + + // UDP from server to vnet1 + TxUdpPacket(vhost->id(), src_ip, + vnet[1]->mdata_ip_addr().to_string().c_str(), 10, 20); + + EXPECT_TRUE(NatValidateFlow(1, vhost->vrf()->GetName().c_str(), + src_ip, + vnet[1]->mdata_ip_addr().to_string().c_str(), + IPPROTO_UDP, 10, 20, 1, "vrf1", + "169.254.169.254", vnet_addr[1], 10, 20, + agent_->fabric_vn_name().c_str(), "vn1", + vhost->flow_key_nh()->id(), + vnet[1]->flow_key_nh()->id())); + + // TCP from server to vnet1 + TxTcpPacket(vhost->id(), src_ip, + vnet[1]->mdata_ip_addr().to_string().c_str(), 10, 20, false); + + EXPECT_TRUE(NatValidateFlow(1, vhost->vrf()->GetName().c_str(), + src_ip, + vnet[1]->mdata_ip_addr().to_string().c_str(), + IPPROTO_TCP, 10, 20, 1, "vrf1", "169.254.169.254", + vnet_addr[1], 10, 20, + agent_->fabric_vn_name().c_str(), "vn1", + vhost->flow_key_nh()->id(), + vnet[1]->flow_key_nh()->id())); + RemoveMetadataService(); + client->WaitForIdle(); +} + // Test for traffic from VM to server TEST_F(FlowTest, VmToServer_1) { SetupMetadataService(); @@ -601,10 +664,9 @@ TEST_F(FlowTest, VmToServer_1) { vnet[1]->mdata_ip_addr().to_string().c_str(), vhost_addr, 10000, MEDATA_NAT_DPORT, "vn1", - Agent::GetInstance()->fabric_vrf_name().c_str(), + agent_->fabric_vn_name().c_str(), vnet[1]->flow_key_nh()->id(), vhost->flow_key_nh()->id())); - // Agent::GetInstance()->fabric_vn_name().c_str())); client->WaitForIdle(); TxUdpPacket(vnet[1]->id(), vnet_addr[1], "169.254.169.254", @@ -1118,7 +1180,7 @@ TEST_F(FlowTest, FlowCleanup_on_intf_del_1) { client->WaitForIdle(); EXPECT_TRUE(FlowGetNat(vhost->vrf()->GetName(), vhost_addr, vnet[7]->mdata_ip_addr().to_string().c_str(), 6, 100, 100, - Agent::GetInstance()->fabric_vrf_name(), "vn7", 2, + agent_->fabric_vn_name(), "vn7", 2, vnet[7]->vrf()->GetName().c_str(), "169.254.169.254", vnet_addr[7], 100, 100, vhost->flow_key_nh()->id(), vnet[7]->flow_key_nh()->id())); @@ -1128,7 +1190,7 @@ TEST_F(FlowTest, FlowCleanup_on_intf_del_1) { client->WaitForIdle(); EXPECT_TRUE(FlowGetNat(vnet[7]->vrf()->GetName(), vnet_addr[7], "169.254.169.254", 6, 10, 80, - "vn7", Agent::GetInstance()->fabric_vrf_name(), 3, + "vn7", agent_->fabric_vn_name(), 3, vhost->vrf()->GetName().c_str(), vnet[7]->mdata_ip_addr().to_string().c_str(), vhost_addr, 10, MEDATA_NAT_DPORT, vnet[7]->flow_key_nh()->id(), @@ -1168,8 +1230,7 @@ TEST_F(FlowTest, FlowCleanup_on_intf_del_2) { vnet[8]->mdata_ip_addr().to_string().c_str(), 100, 100, false, 2); client->WaitForIdle(); EXPECT_TRUE(FlowGetNat(vhost->vrf()->GetName(), vhost_addr, mdata_ip, - 6, 100, 100, Agent::GetInstance()->fabric_vrf_name(), "vn8", 2, - // 6, 100, 100, Agent::GetInstance()->fabric_vn_name(), "vn8", 2, + 6, 100, 100, agent_->fabric_vn_name(), "vn8", 2, "vrf8", "169.254.169.254", vnet_addr[8], 100, 100, vhost->flow_key_nh()->id(), vnet[8]->flow_key_nh()->id())); @@ -1178,8 +1239,7 @@ TEST_F(FlowTest, FlowCleanup_on_intf_del_2) { "169.254.169.254", 10, 80, false, 3); client->WaitForIdle(); EXPECT_TRUE(FlowGetNat("vrf8", vnet_addr[8], "169.254.169.254", 6, 10, 80, - "vn8", Agent::GetInstance()->fabric_vrf_name(), 3, - // "vn8", Agent::GetInstance()->fabric_vn_name(), 3, + "vn8", agent_->fabric_vn_name(), 3, vhost->vrf()->GetName().c_str(), mdata_ip, vhost_addr, 10, MEDATA_NAT_DPORT, vnet[8]->flow_key_nh()->id(), diff --git a/src/vnsw/agent/pkt/test/test_pkt_flow.cc b/src/vnsw/agent/pkt/test/test_pkt_flow.cc index d3d8f89f542..0a06beb245a 100644 --- a/src/vnsw/agent/pkt/test/test_pkt_flow.cc +++ b/src/vnsw/agent/pkt/test/test_pkt_flow.cc @@ -3637,7 +3637,8 @@ int main(int argc, char *argv[]) { PhysicalInterface::CreateReq(Agent::GetInstance()->interface_table(), eth_itf, Agent::GetInstance()->fabric_vrf_name(), - PhysicalInterface::FABRIC); + PhysicalInterface::FABRIC, + PhysicalInterface::ETHERNET, false); client->WaitForIdle(); } diff --git a/src/vnsw/agent/services/arp_entry.cc b/src/vnsw/agent/services/arp_entry.cc index 88f78b7c3a7..da0c68a56ef 100644 --- a/src/vnsw/agent/services/arp_entry.cc +++ b/src/vnsw/agent/services/arp_entry.cc @@ -9,20 +9,46 @@ #include "oper/route_common.h" ArpEntry::ArpEntry(boost::asio::io_service &io, ArpHandler *handler, - ArpKey &key, State state) - : key_(key), state_(state), retry_count_(0), handler_(handler), - arp_timer_(NULL) { - arp_timer_ = TimerManager::CreateTimer(io, "Arp Entry timer", - TaskScheduler::GetInstance()->GetTaskId("Agent::Services"), - PktHandler::ARP); + ArpKey &key, const VrfEntry *vrf, State state, + const Interface *itf) + : io_(io), key_(key), nh_vrf_(vrf), state_(state), retry_count_(0), + handler_(handler), arp_timer_(NULL), interface_(itf) { + if (!IsDerived()) { + arp_timer_ = TimerManager::CreateTimer(io, "Arp Entry timer", + TaskScheduler::GetInstance()->GetTaskId("Agent::Services"), + PktHandler::ARP); + } } ArpEntry::~ArpEntry() { - arp_timer_->Cancel(); - TimerManager::DeleteTimer(arp_timer_); + if (!IsDerived()) { + arp_timer_->Cancel(); + TimerManager::DeleteTimer(arp_timer_); + } +} + +void ArpEntry::HandleDerivedArpRequest() { + ArpProto *arp_proto = handler_->agent()->GetArpProto(); + //Add ArpRoute for Derived entry + AddArpRoute(IsResolved()); + + ArpKey key(key_.ip, nh_vrf_); + ArpEntry *entry = arp_proto->FindArpEntry(key); + if (entry) { + entry->HandleArpRequest(); + } else { + entry = new ArpEntry(io_, handler_.get(), key, nh_vrf_, ArpEntry::INITING, + interface_); + arp_proto->AddArpEntry(entry); + entry->HandleArpRequest(); + } } bool ArpEntry::HandleArpRequest() { + if (IsDerived()) { + HandleDerivedArpRequest(); + return true; + } if (IsResolved()) AddArpRoute(true); else { @@ -36,14 +62,21 @@ bool ArpEntry::HandleArpRequest() { } void ArpEntry::HandleArpReply(const MacAddress &mac) { + + if (IsDerived()) { + /* We don't expect ARP replies in derived Vrf */ + return; + } if ((state_ == ArpEntry::RESOLVING) || (state_ == ArpEntry::ACTIVE) || (state_ == ArpEntry::INITING) || (state_ == ArpEntry::RERESOLVING)) { ArpProto *arp_proto = handler_->agent()->GetArpProto(); arp_timer_->Cancel(); retry_count_ = 0; mac_address_ = mac; - if (state_ == ArpEntry::RESOLVING) + if (state_ == ArpEntry::RESOLVING) { arp_proto->IncrementStatsResolved(); + arp_proto->IncrementStatsResolved(interface_->id()); + } state_ = ArpEntry::ACTIVE; StartTimer(arp_proto->aging_timeout(), ArpProto::AGING_TIMER_EXPIRED); AddArpRoute(true); @@ -77,7 +110,7 @@ bool ArpEntry::RetryExpiry() { bool ArpEntry::AgingExpiry() { Ip4Address ip(key_.ip); const string& vrf_name = key_.vrf->GetName(); - ArpNHKey nh_key(vrf_name, ip); + ArpNHKey nh_key(vrf_name, ip, false); ArpNH *arp_nh = static_cast(handler_->agent()->nexthop_table()-> FindActiveEntry(&nh_key)); if (!arp_nh) { @@ -114,25 +147,49 @@ bool ArpEntry::IsResolved() { return (state_ & (ArpEntry::ACTIVE | ArpEntry::RERESOLVING)); } +bool ArpEntry::IsDerived() { + if (key_.vrf != nh_vrf_) { + return true; + } + return false; +} + void ArpEntry::StartTimer(uint32_t timeout, uint32_t mtype) { arp_timer_->Cancel(); arp_timer_->Start(timeout, boost::bind(&ArpProto::TimerExpiry, handler_->agent()->GetArpProto(), - key_, mtype)); + key_, mtype, interface_)); } void ArpEntry::SendArpRequest() { + assert(!IsDerived()); Agent *agent = handler_->agent(); ArpProto *arp_proto = agent->GetArpProto(); - uint16_t itf_index = arp_proto->ip_fabric_interface_index(); - Ip4Address ip = agent->router_id(); + uint32_t vrf_id = VrfEntry::kInvalidIndex; + uint32_t intf_id = arp_proto->ip_fabric_interface_index(); + Ip4Address ip; + MacAddress smac; + if (interface_->type() == Interface::VM_INTERFACE) { + const VmInterface *vmi = static_cast(interface_); + ip = vmi->GetGateway(); + vrf_id = nh_vrf_->vrf_id(); + if (vmi->parent()) { + intf_id = vmi->parent()->id(); + smac = vmi->parent()->mac(); + } + } else { + ip = agent->router_id(); + VrfEntry *vrf = + agent->vrf_table()->FindVrfFromName(agent->fabric_vrf_name()); + if (vrf) { + vrf_id = vrf->vrf_id(); + } + smac = interface_->mac(); + } - VrfEntry *vrf = - agent->vrf_table()->FindVrfFromName(agent->fabric_vrf_name()); - if (vrf) { - handler_->SendArp(ARPOP_REQUEST, arp_proto->ip_fabric_interface_mac(), - ip.to_ulong(), MacAddress(), key_.ip, itf_index, - vrf->vrf_id()); + if (vrf_id != VrfEntry::kInvalidIndex) { + handler_->SendArp(ARPOP_REQUEST, smac, ip.to_ulong(), + MacAddress(), key_.ip, intf_id, vrf_id); } StartTimer(arp_proto->retry_timeout(), ArpProto::RETRY_TIMER_EXPIRED); @@ -147,7 +204,7 @@ void ArpEntry::AddArpRoute(bool resolved) { Ip4Address ip(key_.ip); const string& vrf_name = key_.vrf->GetName(); - ArpNHKey nh_key(vrf_name, ip); + ArpNHKey nh_key(nh_vrf_->GetName(), ip, false); ArpNH *arp_nh = static_cast(handler_->agent()->nexthop_table()-> FindActiveEntry(&nh_key)); @@ -155,15 +212,43 @@ void ArpEntry::AddArpRoute(bool resolved) { if (arp_nh && arp_nh->GetResolveState() && mac.CompareTo(arp_nh->GetMac()) == 0) { // MAC address unchanged, ignore - return; + if (!IsDerived()) { + return; + } else { + /* Return if the route is already existing */ + InetUnicastRouteKey *rt_key = new InetUnicastRouteKey( + handler_->agent()->local_peer(), vrf_name, ip, 32); + AgentRoute *entry = key_.vrf->GetInet4UnicastRouteTable()-> + FindActiveEntry(rt_key); + delete rt_key; + if (entry) { + return; + } + resolved = true; + } } ARP_TRACE(Trace, "Add", ip.to_string(), vrf_name, mac.ToString()); + AgentRoute *entry = key_.vrf->GetInet4UnicastRouteTable()->FindLPM(ip); + + bool policy = false; + SecurityGroupList sg; + std::string vn = " ";; + if (entry) { + policy = entry->GetActiveNextHop()->PolicyEnabled(); + sg = entry->GetActivePath()->sg_list(); + vn = entry->GetActivePath()->dest_vn_name(); + } - Interface *itf = handler_->agent()->GetArpProto()->ip_fabric_interface(); + const Interface *itf = NULL; + if (interface_->type() == Interface::VM_INTERFACE) { + itf = interface_; + } else { + itf = handler_->agent()->GetArpProto()->ip_fabric_interface(); + } handler_->agent()->fabric_inet4_unicast_table()->ArpRoute( - DBRequest::DB_ENTRY_ADD_CHANGE, ip, mac, - vrf_name, *itf, resolved, 32); + DBRequest::DB_ENTRY_ADD_CHANGE, vrf_name, ip, mac, + nh_vrf_->GetName(), *itf, resolved, 32, policy, vn, sg); } bool ArpEntry::DeleteArpRoute() { @@ -173,7 +258,7 @@ bool ArpEntry::DeleteArpRoute() { Ip4Address ip(key_.ip); const string& vrf_name = key_.vrf->GetName(); - ArpNHKey nh_key(vrf_name, ip); + ArpNHKey nh_key(nh_vrf_->GetName(), ip, false); ArpNH *arp_nh = static_cast(handler_->agent()->nexthop_table()-> FindActiveEntry(&nh_key)); if (!arp_nh) @@ -182,9 +267,17 @@ bool ArpEntry::DeleteArpRoute() { MacAddress mac = mac_address_; ARP_TRACE(Trace, "Delete", ip.to_string(), vrf_name, mac.ToString()); - Interface *itf = handler_->agent()->GetArpProto()->ip_fabric_interface(); handler_->agent()->fabric_inet4_unicast_table()->ArpRoute( - DBRequest::DB_ENTRY_DELETE, ip, mac, vrf_name, - *itf, false, 32); + DBRequest::DB_ENTRY_DELETE, vrf_name, ip, mac, vrf_name, + *interface_, false, 32, false, " ", SecurityGroupList()); return false; } + +void ArpEntry::Resync(bool policy, const std::string &vn, + const SecurityGroupList &sg) { + Ip4Address ip(key_.ip); + handler_->agent()->fabric_inet4_unicast_table()->ArpRoute( + DBRequest::DB_ENTRY_ADD_CHANGE, key_.vrf->GetName(), ip, + mac_address_, nh_vrf_->GetName(), *interface_, IsResolved(), + 32, policy, vn, sg); +} diff --git a/src/vnsw/agent/services/arp_entry.h b/src/vnsw/agent/services/arp_entry.h index 3154982128f..b1776fcf99d 100644 --- a/src/vnsw/agent/services/arp_entry.h +++ b/src/vnsw/agent/services/arp_entry.h @@ -29,12 +29,14 @@ class ArpEntry { }; ArpEntry(boost::asio::io_service &io, ArpHandler *handler, - ArpKey &key, State state); + ArpKey &key, const VrfEntry *vrf, State state, + const Interface *itf); virtual ~ArpEntry(); const ArpKey &key() const { return key_; } State state() const { return state_; } const MacAddress &mac_address() const { return mac_address_; } + const Interface *interface() const { return interface_; } bool HandleArpRequest(); void HandleArpReply(const MacAddress &); @@ -43,18 +45,24 @@ class ArpEntry { void SendGratuitousArp(); bool DeleteArpRoute(); bool IsResolved(); + void Resync(bool policy, const std::string &vn, const SecurityGroupList &sg); private: void StartTimer(uint32_t timeout, uint32_t mtype); void SendArpRequest(); void AddArpRoute(bool resolved); + void HandleDerivedArpRequest(); + bool IsDerived(); + boost::asio::io_service &io_; ArpKey key_; + const VrfEntry *nh_vrf_; MacAddress mac_address_; State state_; int retry_count_; boost::scoped_ptr handler_; Timer *arp_timer_; + const Interface *interface_; DISALLOW_COPY_AND_ASSIGN(ArpEntry); }; diff --git a/src/vnsw/agent/services/arp_handler.cc b/src/vnsw/agent/services/arp_handler.cc index 22e01ef49d4..c7d56dc6a9f 100644 --- a/src/vnsw/agent/services/arp_handler.cc +++ b/src/vnsw/agent/services/arp_handler.cc @@ -87,16 +87,16 @@ bool ArpHandler::HandlePacket() { ARP_TRACE(Error, "Received ARP packet from invalid / inactive interface"); return true; } - if (itf->type() == Interface::VM_INTERFACE) { - const VmInterface *vm_itf = static_cast(itf); - if (!vm_itf->layer3_forwarding()) { - ARP_TRACE(Error, "Received ARP packet on ipv4 disabled interface"); - return true; - } - } - const VrfEntry *vrf = itf->vrf(); + const VrfEntry *vrf = agent()->vrf_table()->FindVrfFromId(pkt_info_->vrf); if (!vrf || !vrf->IsActive()) { + arp_proto->IncrementStatsInvalidVrf(); + ARP_TRACE(Error, "ARP : AgentHdr " + itf->name() + + " has no / inactive VRF "); + return true; + } + const VrfEntry *nh_vrf = itf->vrf(); + if (!nh_vrf || !nh_vrf->IsActive()) { arp_proto->IncrementStatsInvalidVrf(); ARP_TRACE(Error, "ARP : Interface " + itf->name() + " has no / inactive VRF"); @@ -123,6 +123,12 @@ bool ArpHandler::HandlePacket() { arp_addr.to_string()); return true; } + if (route->GetActiveNextHop()->GetType() == NextHop::RESOLVE) { + const ResolveNH *nh = + static_cast(route->GetActiveNextHop()); + itf = nh->interface(); + nh_vrf = itf->vrf(); + } } ArpKey key(arp_tpa_, vrf); @@ -131,11 +137,13 @@ bool ArpHandler::HandlePacket() { switch (arp_cmd) { case ARPOP_REQUEST: { arp_proto->IncrementStatsArpReq(); + arp_proto->IncrementStatsArpRequest(itf->id()); if (entry) { entry->HandleArpRequest(); return true; } else { - entry = new ArpEntry(io_, this, key, ArpEntry::INITING); + entry = new ArpEntry(io_, this, key, nh_vrf, ArpEntry::INITING, + itf); arp_proto->AddArpEntry(entry); entry->HandleArpRequest(); return false; @@ -144,6 +152,7 @@ bool ArpHandler::HandlePacket() { case ARPOP_REPLY: { arp_proto->IncrementStatsArpReplies(); + arp_proto->IncrementStatsArpReply(itf->id()); if (itf->type() == Interface::VM_INTERFACE) { uint32_t ip; memcpy(&ip, arp_->arp_spa, sizeof(ip)); @@ -152,12 +161,17 @@ bool ArpHandler::HandlePacket() { agent()->oper_db()->route_preference_module()-> EnqueueTrafficSeen(Ip4Address(ip), 32, itf->id(), vrf->vrf_id()); + if(entry) { + entry->HandleArpReply(MacAddress(arp_->arp_sha)); + } return true; - } else if(entry) { + } + if(entry) { entry->HandleArpReply(MacAddress(arp_->arp_sha)); return true; - } else { - entry = new ArpEntry(io_, this, key, ArpEntry::INITING); + } else { + entry = new ArpEntry(io_, this, key, nh_vrf, ArpEntry::INITING, + itf); arp_proto->AddArpEntry(entry); entry->HandleArpReply(MacAddress(arp_->arp_sha)); arp_ = NULL; @@ -180,7 +194,7 @@ bool ArpHandler::HandlePacket() { entry->HandleArpReply(MacAddress(arp_->arp_sha)); return true; } else { - entry = new ArpEntry(io_, this, key, ArpEntry::INITING); + entry = new ArpEntry(io_, this, key, key.vrf, ArpEntry::INITING, itf); entry->HandleArpReply(MacAddress(arp_->arp_sha)); arp_proto->AddArpEntry(entry); arp_ = NULL; @@ -195,6 +209,13 @@ bool ArpHandler::HandlePacket() { } } +/* This API is invoked from the following paths + - NextHop notification for ARP_NH + - ARP Timer expiry + - Sending Gratituous ARP for Receive Nexthops + In all these above paths we expect route_vrf and nh_vrf for ArpRoute to + be same + */ bool ArpHandler::HandleMessage() { bool ret = true; ArpProto::ArpIpc *ipc = static_cast(pkt_info_->ipc); @@ -203,11 +224,13 @@ bool ArpHandler::HandleMessage() { case ArpProto::ARP_RESOLVE: { ArpEntry *entry = arp_proto->FindArpEntry(ipc->key); if (!entry) { - entry = new ArpEntry(io_, this, ipc->key, ArpEntry::INITING); + entry = new ArpEntry(io_, this, ipc->key, ipc->key.vrf, + ArpEntry::INITING, ipc->interface); arp_proto->AddArpEntry(entry); ret = false; } arp_proto->IncrementStatsArpReq(); + arp_proto->IncrementStatsArpRequest(ipc->interface->id()); entry->HandleArpRequest(); break; } @@ -215,7 +238,8 @@ bool ArpHandler::HandleMessage() { case ArpProto::ARP_SEND_GRATUITOUS: { if (!arp_proto->gratuitous_arp_entry()) { arp_proto->set_gratuitous_arp_entry( - new ArpEntry(io_, this, ipc->key, ArpEntry::ACTIVE)); + new ArpEntry(io_, this, ipc->key, ipc->key.vrf, + ArpEntry::ACTIVE, ipc->interface)); ret = false; } arp_proto->gratuitous_arp_entry()->SendGratuitousArp(); diff --git a/src/vnsw/agent/services/arp_proto.cc b/src/vnsw/agent/services/arp_proto.cc index b89bb49e7ef..a5fdac88d90 100644 --- a/src/vnsw/agent/services/arp_proto.cc +++ b/src/vnsw/agent/services/arp_proto.cc @@ -80,8 +80,10 @@ void ArpProto::VrfNotify(DBTablePartBase *part, DBEntryBase *entry) { } } -ArpDBState::ArpDBState(ArpVrfState *vrf_state, uint32_t vrf_id, IpAddress ip) : - vrf_state_(vrf_state), arp_req_timer_(NULL), vrf_id_(vrf_id), vm_ip_(ip) { +ArpDBState::ArpDBState(ArpVrfState *vrf_state, uint32_t vrf_id, IpAddress ip, + uint8_t plen) : vrf_state_(vrf_state), + arp_req_timer_(NULL), vrf_id_(vrf_id), vm_ip_(ip), plen_(plen), + sg_list_(0), policy_(false), resolve_route_(false) { } ArpDBState::~ArpDBState() { @@ -156,7 +158,6 @@ void ArpDBState::SendArpRequestForAllIntf(const InetUnicastRouteEntry *route) { //Ignore non vm interface nexthop continue; } - if (path->subnet_gw_ip().is_v4() == false) { continue; } @@ -188,6 +189,68 @@ void ArpDBState::SendArpRequestForAllIntf(const InetUnicastRouteEntry *route) { } } +void ArpDBState::UpdateArpRoutes(const InetUnicastRouteEntry *rt) { + int plen = rt->plen(); + uint32_t start_ip = rt->addr().to_v4().to_ulong(); + ArpKey start_key(start_ip, rt->vrf()); + + ArpProto::ArpIterator start_iter = + vrf_state_->arp_proto->FindUpperBoundArpEntry(start_key); + + if (start_iter->first.vrf != rt->vrf()) { + return; + } + + + while (IsIp4SubnetMember(Ip4Address(start_iter->first.ip), + rt->addr().to_v4(), plen)) { + start_iter->second->Resync(policy_, vn_, sg_list_); + start_iter++; + } +} + +void ArpDBState::Delete(const InetUnicastRouteEntry *rt) { + int plen = rt->plen(); + uint32_t start_ip = rt->addr().to_v4().to_ulong(); + + ArpKey start_key(start_ip, rt->vrf()); + + ArpProto::ArpIterator start_iter = + vrf_state_->arp_proto->FindUpperBoundArpEntry(start_key); + + if (start_iter->first.vrf != rt->vrf()) { + return; + } + + while (IsIp4SubnetMember(Ip4Address(start_iter->first.ip), + rt->addr().to_v4(), plen)) { + ArpProto::ArpIterator tmp = start_iter++; + if (tmp->second->DeleteArpRoute()) { + vrf_state_->arp_proto->DeleteArpEntry(tmp->second); + } + } +} + +void ArpDBState::Update(const InetUnicastRouteEntry *rt) { + if (rt->GetActiveNextHop()->GetType() == NextHop::RESOLVE) { + resolve_route_ = true; + } + + bool policy = rt->GetActiveNextHop()->PolicyEnabled(); + const SecurityGroupList sg = rt->GetActivePath()->sg_list(); + + + if (policy_ != policy || sg != sg_list_ || + vn_ != rt->GetActivePath()->dest_vn_name()) { + policy_ = policy; + sg_list_ = sg; + vn_ = rt->GetActivePath()->dest_vn_name(); + if (resolve_route_) { + UpdateArpRoutes(rt); + } + } +} + void ArpVrfState::RouteUpdate(DBTablePartBase *part, DBEntryBase *entry) { InetUnicastRouteEntry *route = static_cast(entry); @@ -203,13 +266,15 @@ void ArpVrfState::RouteUpdate(DBTablePartBase *part, DBEntryBase *entry) { arp_proto->del_gratuitous_arp_entry(); } entry->ClearState(part->parent(), route_table_listener_id); + state->Delete(route); delete state; } return; } if (!state) { - state = new ArpDBState(this, route->vrf_id(), route->addr()); + state = new ArpDBState(this, route->vrf_id(), route->addr(), + route->plen()); entry->SetState(part->parent(), route_table_listener_id, state); } @@ -218,12 +283,14 @@ void ArpVrfState::RouteUpdate(DBTablePartBase *part, DBEntryBase *entry) { arp_proto->del_gratuitous_arp_entry(); //Send Grat ARP arp_proto->SendArpIpc(ArpProto::ARP_SEND_GRATUITOUS, - route->addr().to_v4().to_ulong(), route->vrf()); + route->addr().to_v4().to_ulong(), route->vrf(), + arp_proto->ip_fabric_interface()); } //Check if there is a local VM path, if yes send a //ARP request, to trigger route preference state machine if (state && route->vrf()->GetName() != agent->fabric_vrf_name()) { + state->Update(route); state->SendArpRequestForAllIntf(route); } } @@ -258,16 +325,26 @@ ArpVrfState::ArpVrfState(Agent *agent_ptr, ArpProto *proto, VrfEntry *vrf_entry, void ArpProto::InterfaceNotify(DBEntryBase *entry) { Interface *itf = static_cast(entry); if (entry->IsDeleted()) { + InterfaceArpMap::iterator it = interface_arp_map_.find(itf->id()); + if (it != interface_arp_map_.end()) { + InterfaceArpInfo &intf_entry = it->second; + ArpKeySet::iterator key_it = intf_entry.arp_key_list.begin(); + while (key_it != intf_entry.arp_key_list.end()) { + ArpKey key = *key_it; + ++key_it; + ArpIterator arp_it = arp_cache_.find(key); + if (arp_it != arp_cache_.end()) { + ArpEntry *arp_entry = arp_it->second; + if (arp_entry->DeleteArpRoute()) { + DeleteArpEntry(arp_it); + } + } + } + intf_entry.arp_key_list.clear(); + interface_arp_map_.erase(it); + } if (itf->type() == Interface::PHYSICAL && itf->name() == agent_->fabric_interface_name()) { - for (ArpProto::ArpIterator it = arp_cache_.begin(); - it != arp_cache_.end();) { - ArpEntry *arp_entry = it->second; - if (arp_entry->DeleteArpRoute()) { - it = DeleteArpEntry(it); - } else - it++; - } set_ip_fabric_interface(NULL); set_ip_fabric_interface_index(-1); } @@ -285,6 +362,53 @@ void ArpProto::InterfaceNotify(DBEntryBase *entry) { } } +ArpProto::InterfaceArpInfo& ArpProto::ArpMapIndexToEntry(uint32_t idx) { + InterfaceArpMap::iterator it = interface_arp_map_.find(idx); + if (it == interface_arp_map_.end()) { + InterfaceArpInfo entry; + std::pair ret; + ret = interface_arp_map_.insert(InterfaceArpPair(idx, entry)); + return ret.first->second; + } else { + return it->second; + } +} + +void ArpProto::IncrementStatsArpRequest(uint32_t idx) { + InterfaceArpInfo &entry = ArpMapIndexToEntry(idx); + entry.stats.arp_req++; +} + +void ArpProto::IncrementStatsArpReply(uint32_t idx) { + InterfaceArpInfo &entry = ArpMapIndexToEntry(idx); + entry.stats.arp_replies++; +} + +void ArpProto::IncrementStatsResolved(uint32_t idx) { + InterfaceArpInfo &entry = ArpMapIndexToEntry(idx); + entry.stats.resolved++; +} + +uint32_t ArpProto::ArpRequestStatsCounter(uint32_t idx) { + InterfaceArpInfo &entry = ArpMapIndexToEntry(idx); + return entry.stats.arp_req; +} + +uint32_t ArpProto::ArpReplyStatsCounter(uint32_t idx) { + InterfaceArpInfo &entry = ArpMapIndexToEntry(idx); + return entry.stats.arp_replies; +} + +uint32_t ArpProto::ArpResolvedStatsCounter(uint32_t idx) { + InterfaceArpInfo &entry = ArpMapIndexToEntry(idx); + return entry.stats.resolved; +} + +void ArpProto::ClearInterfaceArpStats(uint32_t idx) { + InterfaceArpInfo &entry = ArpMapIndexToEntry(idx); + entry.stats.Reset(); +} + void ArpProto::NextHopNotify(DBEntryBase *entry) { NextHop *nh = static_cast(entry); @@ -293,10 +417,10 @@ void ArpProto::NextHopNotify(DBEntryBase *entry) { ArpNH *arp_nh = (static_cast(nh)); if (arp_nh->IsDeleted()) { SendArpIpc(ArpProto::ARP_DELETE, arp_nh->GetIp()->to_ulong(), - arp_nh->GetVrf()); + arp_nh->GetVrf(), arp_nh->GetInterface()); } else if (arp_nh->IsValid() == false) { SendArpIpc(ArpProto::ARP_RESOLVE, arp_nh->GetIp()->to_ulong(), - arp_nh->GetVrf()); + arp_nh->GetVrf(), arp_nh->GetInterface()); } break; } @@ -306,9 +430,10 @@ void ArpProto::NextHopNotify(DBEntryBase *entry) { } } -bool ArpProto::TimerExpiry(ArpKey &key, uint32_t timer_type) { +bool ArpProto::TimerExpiry(ArpKey &key, uint32_t timer_type, + const Interface* itf) { if (arp_cache_.find(key) != arp_cache_.end()) - SendArpIpc((ArpProto::ArpMsgType)timer_type, key); + SendArpIpc((ArpProto::ArpMsgType)timer_type, key, itf); return false; } @@ -327,19 +452,34 @@ void ArpProto::del_gratuitous_arp_entry() { } } -void ArpProto::SendArpIpc(ArpProto::ArpMsgType type, - in_addr_t ip, const VrfEntry *vrf) { - ArpIpc *ipc = new ArpIpc(type, ip, vrf); +void ArpProto::SendArpIpc(ArpProto::ArpMsgType type, in_addr_t ip, + const VrfEntry *vrf, const Interface* itf) { + ArpIpc *ipc = new ArpIpc(type, ip, vrf, itf); agent_->pkt()->pkt_handler()->SendMessage(PktHandler::ARP, ipc); } -void ArpProto::SendArpIpc(ArpProto::ArpMsgType type, ArpKey &key) { - ArpIpc *ipc = new ArpIpc(type, key); +void ArpProto::SendArpIpc(ArpProto::ArpMsgType type, ArpKey &key, + const Interface* itf) { + ArpIpc *ipc = new ArpIpc(type, key, itf); agent_->pkt()->pkt_handler()->SendMessage(PktHandler::ARP, ipc); } bool ArpProto::AddArpEntry(ArpEntry *entry) { - return arp_cache_.insert(ArpCachePair(entry->key(), entry)).second; + bool ret = arp_cache_.insert(ArpCachePair(entry->key(), entry)).second; + uint32_t intf_id = entry->interface()->id(); + InterfaceArpMap::iterator it = interface_arp_map_.find(intf_id); + if (it == interface_arp_map_.end()) { + InterfaceArpInfo intf_entry; + intf_entry.arp_key_list.insert(entry->key()); + interface_arp_map_.insert(InterfaceArpPair(intf_id, intf_entry)); + } else { + InterfaceArpInfo &intf_entry = it->second; + ArpKeySet::iterator key_it = intf_entry.arp_key_list.find(entry->key()); + if (key_it == intf_entry.arp_key_list.end()) { + intf_entry.arp_key_list.insert(entry->key()); + } + } + return ret; } bool ArpProto::DeleteArpEntry(ArpEntry *entry) { @@ -389,3 +529,13 @@ void ArpProto::ValidateAndClearVrfState(VrfEntry *vrf) { vrf_table_listener_id_); } } + +ArpProto::ArpIterator +ArpProto::FindUpperBoundArpEntry(const ArpKey &key) { + return arp_cache_.upper_bound(key); +} + +ArpProto::ArpIterator +ArpProto::FindLowerBoundArpEntry(const ArpKey &key) { + return arp_cache_.lower_bound(key); +} diff --git a/src/vnsw/agent/services/arp_proto.h b/src/vnsw/agent/services/arp_proto.h index 00ce186f8b2..b86957cbddb 100644 --- a/src/vnsw/agent/services/arp_proto.h +++ b/src/vnsw/agent/services/arp_proto.h @@ -26,6 +26,7 @@ class ArpProto : public Proto { typedef std::pair ArpCachePair; typedef std::map::iterator ArpIterator; typedef boost::function Callback; + typedef std::set ArpKeySet; enum ArpMsgType { ARP_RESOLVE, @@ -37,12 +38,14 @@ class ArpProto : public Proto { }; struct ArpIpc : InterTaskMsg { - ArpIpc(ArpProto::ArpMsgType msg, ArpKey &akey) - : InterTaskMsg(msg), key(akey) {} - ArpIpc(ArpProto::ArpMsgType msg, in_addr_t ip, const VrfEntry *vrf) : - InterTaskMsg(msg), key(ip, vrf) {} + ArpIpc(ArpProto::ArpMsgType msg, ArpKey &akey, const Interface* itf) + : InterTaskMsg(msg), key(akey), interface(itf) {} + ArpIpc(ArpProto::ArpMsgType msg, in_addr_t ip, const VrfEntry *vrf, + const Interface* itf) : + InterTaskMsg(msg), key(ip, vrf), interface(itf) {} ArpKey key; + const Interface *interface; }; struct ArpStats { @@ -67,19 +70,28 @@ class ArpProto : public Proto { uint32_t vm_arp_req; }; + struct InterfaceArpInfo { + InterfaceArpInfo() : arp_key_list(), stats() {} + ArpKeySet arp_key_list; + ArpStats stats; + }; + typedef std::map InterfaceArpMap; + typedef std::pair InterfaceArpPair; + void Shutdown(); ArpProto(Agent *agent, boost::asio::io_service &io, bool run_with_vrouter); virtual ~ArpProto(); ProtoHandler *AllocProtoHandler(boost::shared_ptr info, boost::asio::io_service &io); - bool TimerExpiry(ArpKey &key, uint32_t timer_type); + bool TimerExpiry(ArpKey &key, uint32_t timer_type, const Interface *itf); bool AddArpEntry(ArpEntry *entry); bool DeleteArpEntry(ArpEntry *entry); ArpEntry *FindArpEntry(const ArpKey &key); std::size_t GetArpCacheSize() { return arp_cache_.size(); } const ArpCache& arp_cache() { return arp_cache_; } + const InterfaceArpMap& interface_arp_map() { return interface_arp_map_; } Interface *ip_fabric_interface() const { return ip_fabric_interface_; } uint16_t ip_fabric_interface_index() const { @@ -126,22 +138,34 @@ class ArpProto : public Proto { const ArpStats &GetStats() const { return arp_stats_; } void ClearStats() { arp_stats_.Reset(); } + void IncrementStatsArpRequest(uint32_t idx); + void IncrementStatsArpReply(uint32_t idx); + void IncrementStatsResolved(uint32_t idx); + InterfaceArpInfo& ArpMapIndexToEntry(uint32_t idx); + uint32_t ArpRequestStatsCounter(uint32_t idx); + uint32_t ArpReplyStatsCounter(uint32_t idx); + uint32_t ArpResolvedStatsCounter(uint32_t idx); + void ClearInterfaceArpStats(uint32_t idx); + uint16_t max_retries() const { return max_retries_; } uint32_t retry_timeout() const { return retry_timeout_; } uint32_t aging_timeout() const { return aging_timeout_; } void set_max_retries(uint16_t retries) { max_retries_ = retries; } void set_retry_timeout(uint32_t timeout) { retry_timeout_ = timeout; } void set_aging_timeout(uint32_t timeout) { aging_timeout_ = timeout; } - void SendArpIpc(ArpProto::ArpMsgType type, - in_addr_t ip, const VrfEntry *vrf); + void SendArpIpc(ArpProto::ArpMsgType type, in_addr_t ip, + const VrfEntry *vrf, const Interface* itf); void ValidateAndClearVrfState(VrfEntry *vrf); + ArpIterator FindUpperBoundArpEntry(const ArpKey &key); + ArpIterator FindLowerBoundArpEntry(const ArpKey &key); private: void VrfNotify(DBTablePartBase *part, DBEntryBase *entry); void NextHopNotify(DBEntryBase *entry); void InterfaceNotify(DBEntryBase *entry); void RouteUpdate(DBTablePartBase *part, DBEntryBase *entry); - void SendArpIpc(ArpProto::ArpMsgType type, ArpKey &key); + void SendArpIpc(ArpProto::ArpMsgType type, ArpKey &key, + const Interface* itf); ArpProto::ArpIterator DeleteArpEntry(ArpProto::ArpIterator iter); ArpCache arp_cache_; @@ -155,6 +179,7 @@ class ArpProto : public Proto { DBTableBase::ListenerId interface_table_listener_id_; DBTableBase::ListenerId nexthop_table_listener_id_; std::map route_table_listener_; + InterfaceArpMap interface_arp_map_; uint16_t max_retries_; uint32_t retry_timeout_; // milli seconds @@ -191,18 +216,26 @@ class ArpDBState : public DBState { typedef std::map WaitForTrafficIntfMap; ArpDBState(ArpVrfState *vrf_state, uint32_t vrf_id, - IpAddress vm_ip_addr); + IpAddress vm_ip_addr, uint8_t plen); ~ArpDBState(); bool SendArpRequest(); void SendArpRequestForAllIntf(const InetUnicastRouteEntry *route); void StartTimer(); + void Update(const InetUnicastRouteEntry *route); + void UpdateArpRoutes(const InetUnicastRouteEntry *route); + void Delete(const InetUnicastRouteEntry *rt); private: ArpVrfState *vrf_state_; Timer *arp_req_timer_; uint32_t vrf_id_; IpAddress vm_ip_; + uint8_t plen_; IpAddress gw_ip_; + SecurityGroupList sg_list_; + bool policy_; + bool resolve_route_; + std::string vn_; WaitForTrafficIntfMap wait_for_traffic_map_; }; #endif // vnsw_agent_arp_proto_hpp diff --git a/src/vnsw/agent/services/dhcp_handler.cc b/src/vnsw/agent/services/dhcp_handler.cc index 84d7b7b054d..63acc2c5f06 100644 --- a/src/vnsw/agent/services/dhcp_handler.cc +++ b/src/vnsw/agent/services/dhcp_handler.cc @@ -549,7 +549,7 @@ bool DhcpHandler::FindLeaseData() { // Change client name to VM name; this is the name assigned to the VM config_.client_name_ = vm_itf_->vm_name(); FindDomainName(ip); - if (vm_itf_->ipv4_active()) { + if (vm_itf_->ipv4_active() || vm_itf_->sub_type() == VmInterface::TOR) { if (vm_itf_->fabric_port()) { InetUnicastRouteEntry *rt = InetUnicastAgentRouteTable::FindResolveRoute( @@ -579,7 +579,10 @@ bool DhcpHandler::FindLeaseData() { if (IsIp4SubnetMember(ip, ipam[i].ip_prefix.to_v4(), ipam[i].plen)) { Ip4Address default_gw = ipam[i].default_gw.to_v4(); - FillDhcpInfo(ip, ipam[i].plen, default_gw, default_gw); + Ip4Address service_address = ipam[i].dns_server.to_v4(); + if (service_address.is_unspecified()) + service_address = default_gw; + FillDhcpInfo(ip, ipam[i].plen, default_gw, service_address); return true; } } @@ -978,7 +981,10 @@ uint16_t DhcpHandler::FillDhcpResponse(const MacAddress &dest_mac, void DhcpHandler::SendDhcpResponse() { // TODO: If giaddr is set, what to do ? - in_addr_t src_ip = htonl(config_.gw_addr.to_v4().to_ulong()); + // In TSN, the source address for DHCP response should be the address + // in the subnet reserved for service node. Otherwise, it will be the + // GW address. dns_addr field has this address, use it as the source IP. + in_addr_t src_ip = htonl(config_.dns_addr.to_v4().to_ulong()); in_addr_t dest_ip = 0xFFFFFFFF; in_addr_t yiaddr = htonl(config_.ip_addr.to_v4().to_ulong()); in_addr_t siaddr = src_ip; @@ -1007,8 +1013,13 @@ void DhcpHandler::SendDhcpResponse() { UpdateStats(); FillDhcpResponse(dest_mac, src_ip, dest_ip, siaddr, yiaddr); - Send(GetInterfaceIndex(), pkt_info_->vrf, AgentHdr::TX_SWITCH, - PktHandler::DHCP); + uint16_t interface = + (pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) ? + (uint16_t)pkt_info_->agent_hdr.cmd_param : GetInterfaceIndex(); + uint16_t command = + (pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) ? + (uint16_t)AgentHdr::TX_ROUTE : AgentHdr::TX_SWITCH; + Send(interface, pkt_info_->vrf, command, PktHandler::DHCP); } // Check if the option is requested by the client or not diff --git a/src/vnsw/agent/services/dhcpv6_handler.cc b/src/vnsw/agent/services/dhcpv6_handler.cc index 879ed9ed64e..ee615c75a72 100644 --- a/src/vnsw/agent/services/dhcpv6_handler.cc +++ b/src/vnsw/agent/services/dhcpv6_handler.cc @@ -478,7 +478,10 @@ bool Dhcpv6Handler::FindLeaseData() { if (IsIp6SubnetMember(ip, ipam[i].ip_prefix.to_v6(), ipam[i].plen)) { Ip6Address default_gw = ipam[i].default_gw.to_v6(); - FillDhcpInfo(ip, ipam[i].plen, default_gw, default_gw); + Ip6Address service_address = ipam[i].dns_server.to_v6(); + if (service_address.is_unspecified()) + service_address = default_gw; + FillDhcpInfo(ip, ipam[i].plen, default_gw, service_address); return true; } } @@ -620,10 +623,19 @@ uint16_t Dhcpv6Handler::FillDhcpResponse(const MacAddress &dest_mac, void Dhcpv6Handler::SendDhcpResponse() { UpdateStats(); - FillDhcpResponse(MacAddress(pkt_info_->eth->ether_shost), config_.gw_addr.to_v6(), + // In TSN, the source address for DHCP response should be the address + // in the subnet reserved for service node. Otherwise, it will be the + // GW address. dns_addr field has this address, use it as the source IP. + FillDhcpResponse(MacAddress(pkt_info_->eth->ether_shost), + config_.dns_addr.to_v6(), pkt_info_->ip_saddr.to_v6()); - Send(GetInterfaceIndex(), pkt_info_->vrf, - AgentHdr::TX_SWITCH, PktHandler::DHCPV6); + uint16_t interface = + (pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) ? + (uint16_t)pkt_info_->agent_hdr.cmd_param : GetInterfaceIndex(); + uint16_t command = + (pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) ? + (uint16_t)AgentHdr::TX_ROUTE : AgentHdr::TX_SWITCH; + Send(interface, pkt_info_->vrf, command, PktHandler::DHCPV6); } void Dhcpv6Handler::UpdateStats() { diff --git a/src/vnsw/agent/services/dns_handler.cc b/src/vnsw/agent/services/dns_handler.cc index d55b48039c3..52f3c037c40 100644 --- a/src/vnsw/agent/services/dns_handler.cc +++ b/src/vnsw/agent/services/dns_handler.cc @@ -797,8 +797,13 @@ void DnsHandler::SendDnsResponse() { (agent()->interface_table()->FindActiveEntry(&key)); if (pkt_itf) { UpdateStats(); - Send(pkt_info_->GetAgentHdr().ifindex, pkt_info_->vrf, - AgentHdr::TX_SWITCH, PktHandler::DNS); + uint16_t interface = + (pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) ? + (uint16_t)pkt_info_->agent_hdr.cmd_param : GetInterfaceIndex(); + uint16_t command = + (pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) ? + (uint16_t)AgentHdr::TX_ROUTE : AgentHdr::TX_SWITCH; + Send(interface, pkt_info_->vrf, command, PktHandler::DNS); } else { agent()->GetDnsProto()->IncrStatsDrop(); } diff --git a/src/vnsw/agent/services/icmp_handler.cc b/src/vnsw/agent/services/icmp_handler.cc index c29fa986fb7..233222717cd 100644 --- a/src/vnsw/agent/services/icmp_handler.cc +++ b/src/vnsw/agent/services/icmp_handler.cc @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -65,8 +66,7 @@ void IcmpHandler::SendResponse(VmInterface *vm_intf) { char icmp_payload[icmp_len_]; memcpy(icmp_payload, icmp_, icmp_len_); - // Retain the agent-header before ethernet header - uint16_t len = (char *)pkt_info_->eth - (char *)pkt_info_->pkt; + uint16_t len = 0; // Form ICMP Packet with following // EthHdr - IP Header - ICMP Header @@ -92,6 +92,11 @@ void IcmpHandler::SendResponse(VmInterface *vm_intf) { IcmpChecksum((char *)hdr, icmp_len_); pkt_info_->set_len(len); - Send(GetInterfaceIndex(), pkt_info_->vrf, AgentHdr::TX_SWITCH, - PktHandler::ICMP); + uint16_t interface = + ((pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) ? + (uint16_t)pkt_info_->agent_hdr.cmd_param : GetInterfaceIndex()); + uint16_t command = + ((pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) ? + AgentHdr::TX_ROUTE : AgentHdr::TX_SWITCH); + Send(interface, pkt_info_->vrf, command, PktHandler::ICMP); } diff --git a/src/vnsw/agent/services/services.sandesh b/src/vnsw/agent/services/services.sandesh index c52ad8a51d3..0e25da01aee 100644 --- a/src/vnsw/agent/services/services.sandesh +++ b/src/vnsw/agent/services/services.sandesh @@ -36,11 +36,26 @@ request sandesh ShowAllInfo { request sandesh ClearAllInfo { } +struct InterfaceArpStats { + 1: u32 interface_index; + 2: u32 arp_requests; + 3: u32 arp_replies; + 4: u32 arp_resolved; +} + +request sandesh InterfaceArpStatsReq { + 1: i32 interface_index = -1; +} + request sandesh PktTraceInfo { 1: u32 num_buffers = 16; 2: u32 flow_num_buffers = 16; } +response sandesh InterfaceArpStatsResponse { + 1: list stats_list; +} + response sandesh PktStats { 1: i32 total_rcvd; 2: i32 dhcp_rcvd; diff --git a/src/vnsw/agent/services/services_sandesh.cc b/src/vnsw/agent/services/services_sandesh.cc index 6a35d7d6c02..84af64876c2 100644 --- a/src/vnsw/agent/services/services_sandesh.cc +++ b/src/vnsw/agent/services/services_sandesh.cc @@ -263,7 +263,7 @@ uint16_t ServicesSandesh::FillVrouterHdr(PktTrace::Pkt &pkt, VrouterHdr &resp) { { { "switch", "route", "arp", "l2-protocol", "trap-nexthop", "trap-resolve", "trap-flow-miss", "trap-l3-protocol", "trap-diag", "trap-ecmp-resolve", "trap_source_mismatch", - "trap-dont-fragment" } }; + "trap-dont-fragment", "tor-control" } }; uint8_t *ptr = pkt.pkt; AgentHdr *hdr = reinterpret_cast(ptr); resp.ifindex = hdr->ifindex; @@ -1088,3 +1088,38 @@ bool ArpSandesh::SetArpEntry(const ArpKey &key, const ArpEntry *entry) { } return true; } + +void ArpSandesh::SetInterfaceArpStatsEntry( + ArpProto::InterfaceArpMap::const_iterator &it, + std::vector &list) { + InterfaceArpStats data; + data.set_interface_index(it->first); + data.set_arp_requests(it->second.stats.arp_req); + data.set_arp_replies(it->second.stats.arp_replies); + data.set_arp_resolved(it->second.stats.resolved); + list.push_back(data); +} + +void InterfaceArpStatsReq::HandleRequest() const { + InterfaceArpStatsResponse *resp = new InterfaceArpStatsResponse(); + resp->set_context(context()); + ArpSandesh arp_sandesh(resp); + const ArpProto::InterfaceArpMap &imap = + (Agent::GetInstance()->GetArpProto()->interface_arp_map()); + std::vector &list = + const_cast&>(resp->get_stats_list()); + if (get_interface_index() != -1) { + ArpProto::InterfaceArpMap::const_iterator it = imap.find + (get_interface_index()); + if (it != imap.end()) { + arp_sandesh.SetInterfaceArpStatsEntry(it, list); + } + arp_sandesh.Response(); + return; + } + for (ArpProto::InterfaceArpMap::const_iterator it = imap.begin(); + it != imap.end(); it++) { + arp_sandesh.SetInterfaceArpStatsEntry(it, list); + } + arp_sandesh.Response(); +} diff --git a/src/vnsw/agent/services/services_sandesh.h b/src/vnsw/agent/services/services_sandesh.h index aacd78d3de6..da1f3955e8e 100644 --- a/src/vnsw/agent/services/services_sandesh.h +++ b/src/vnsw/agent/services/services_sandesh.h @@ -76,6 +76,9 @@ class ArpSandesh { ArpSandesh(SandeshResponse *resp) : iter_(0), resp_(resp) {}; bool SetArpEntry(const ArpKey &key, const ArpEntry *entry); void Response() { resp_->Response(); } + void SetInterfaceArpStatsEntry( + ArpProto::InterfaceArpMap::const_iterator &it, + std::vector &list); private: int iter_; diff --git a/src/vnsw/agent/services/test/arp_test.cc b/src/vnsw/agent/services/test/arp_test.cc index 9f621a869b5..7e2b4968df5 100644 --- a/src/vnsw/agent/services/test/arp_test.cc +++ b/src/vnsw/agent/services/test/arp_test.cc @@ -162,16 +162,19 @@ class ArpTest : public ::testing::Test { } void SendArpMessage(ArpProto::ArpMsgType type, uint32_t addr) { + PhysicalInterfaceKey key(Agent::GetInstance()->fabric_interface_name()); + Interface *eth = static_cast + (Agent::GetInstance()->interface_table()->FindActiveEntry(&key)); ArpProto::ArpIpc *ipc = new ArpProto::ArpIpc(type, addr, Agent::GetInstance()->vrf_table()-> - FindVrfFromName(Agent::GetInstance()->fabric_vrf_name())); + FindVrfFromName(Agent::GetInstance()->fabric_vrf_name()), eth); Agent::GetInstance()->pkt()->pkt_handler()->SendMessage(PktHandler::ARP, ipc); } bool FindArpNHEntry(uint32_t addr, const string &vrf_name, bool validate = false) { Ip4Address ip(addr); - ArpNHKey key(vrf_name, ip); + ArpNHKey key(vrf_name, ip, false); ArpNH *arp_nh = static_cast(Agent::GetInstance()-> nexthop_table()-> FindActiveEntry(&key)); @@ -201,10 +204,12 @@ class ArpTest : public ::testing::Test { void ArpNHUpdate(DBRequest::DBOperation op, in_addr_t addr) { Ip4Address ip(addr); - InetUnicastAgentRouteTable::ArpRoute(op, ip, MacAddress(), + InetUnicastAgentRouteTable::ArpRoute(op, + Agent::GetInstance()->fabric_vrf_name(), + ip, MacAddress(), Agent::GetInstance()->fabric_vrf_name(), *Agent::GetInstance()->GetArpProto()->ip_fabric_interface(), - false, 32); + false, 32, false, "", SecurityGroupList()); } void TunnelNH(DBRequest::DBOperation op, uint32_t saddr, uint32_t daddr) { @@ -513,7 +518,7 @@ TEST_F(ArpTest, ArpItfDeleteTest) { WAIT_FOR(500, 1000, (VrfFind("vrf2") == false)); } #endif - +#if 0 //Test to verify sending of ARP request on new interface addition TEST_F(ArpTest, ArpReqOnVmInterface) { Agent *agent = Agent::GetInstance(); @@ -638,8 +643,291 @@ TEST_F(ArpTest, ArpReqOnVmInterface_2) { WAIT_FOR(500, 1000, (agent->vn_table()->Size() == 0)); WAIT_FOR(500, 1000, (VrfFind("vrf1") == false)); } +#endif + +//Test to check update on resolve route, would result +//in arp routes also getting updated +TEST_F(ArpTest, SubnetResolveWithoutPolicy) { + struct PortInfo input1[] = { + {"vnet8", 8, "8.1.1.1", "00:00:00:01:01:01", 1, 1} + }; + + client->Reset(); + CreateVmportWithEcmp(input1, 1); + client->WaitForIdle(); + EXPECT_TRUE(VmPortActive(input1, 0)); + EXPECT_TRUE(VmPortFind(8)); + client->Reset(); + + //Add a link to interface subnet and ensure resolve route is added + AddSubnetType("subnet", 1, "8.1.1.0", 24); + AddLink("virtual-machine-interface", input1[0].name, + "subnet", "subnet"); + client->WaitForIdle(); + EXPECT_TRUE(VmPortActive(input1, 0)); + EXPECT_TRUE(RouteFind("vrf1", "8.1.1.0", 24)); + + Ip4Address sip = Ip4Address::from_string("8.1.1.1"); + Ip4Address dip = Ip4Address::from_string("8.1.1.2"); + VmInterface *vintf = VmInterfaceGet(8); + SendArpReq(vintf->id(), vintf->vrf()->vrf_id(), sip.to_ulong(), dip.to_ulong()); + client->WaitForIdle(); + WAIT_FOR(500, 1000, RouteFind("vrf1", "8.1.1.2", 32) == true); + + AgentRoute *rt = RouteGet("vrf1", dip, 32); + EXPECT_TRUE(rt->GetActiveNextHop()->GetType() == NextHop::ARP); + const ArpNH *arp_nh = static_cast(rt->GetActiveNextHop()); + EXPECT_TRUE(arp_nh->GetInterface() == vintf); + EXPECT_TRUE(arp_nh->PolicyEnabled() == false); + EXPECT_TRUE(rt->GetActivePath()->dest_vn_name() == "vn1"); + + DelLink("virtual-machine-interface", input1[0].name, + "subnet", "subnet"); + client->WaitForIdle(); + DeleteVmportEnv(input1, 1, true); + client->WaitForIdle(); + WAIT_FOR(500, 1000, RouteFind("vrf1", "8.1.1.2", 32) == false); + + EXPECT_FALSE(VmPortFind(8)); + VmInterfaceKey key(AgentKey::ADD_DEL_CHANGE, MakeUuid(8), ""); + WAIT_FOR(100, 1000, (Agent::GetInstance()->interface_table()->Find(&key, true) + == NULL)); + client->Reset(); +} + +//Test to check update on resolve route, would result +//in arp routes also getting updated +TEST_F(ArpTest, SubnetResolveWithPolicy) { + struct PortInfo input1[] = { + {"vnet8", 8, "8.1.1.1", "00:00:00:01:01:01", 1, 1} + }; + + client->Reset(); + //Create VM interface with policy + CreateVmportWithEcmp(input1, 1, 1); + client->WaitForIdle(); + EXPECT_TRUE(VmPortActive(input1, 0)); + EXPECT_TRUE(VmPortFind(8)); + client->Reset(); + + //Add a link to interface subnet and ensure resolve route is added + AddSubnetType("subnet", 1, "8.1.1.0", 24); + AddLink("virtual-machine-interface", input1[0].name, + "subnet", "subnet"); + client->WaitForIdle(); + EXPECT_TRUE(VmPortActive(input1, 0)); + EXPECT_TRUE(RouteFind("vrf1", "8.1.1.0", 24)); + + Ip4Address sip = Ip4Address::from_string("8.1.1.1"); + Ip4Address dip = Ip4Address::from_string("8.1.1.2"); + VmInterface *vintf = VmInterfaceGet(8); + SendArpReq(vintf->id(), vintf->vrf()->vrf_id(), sip.to_ulong(), dip.to_ulong()); + client->WaitForIdle(); + WAIT_FOR(500, 1000, RouteFind("vrf1", "8.1.1.2", 32) == true); + + AgentRoute *rt = RouteGet("vrf1", dip, 32); + EXPECT_TRUE(rt->GetActiveNextHop()->GetType() == NextHop::ARP); + const ArpNH *arp_nh = static_cast(rt->GetActiveNextHop()); + EXPECT_TRUE(arp_nh->GetInterface() == vintf); + EXPECT_TRUE(arp_nh->PolicyEnabled() == true); + EXPECT_TRUE(rt->GetActivePath()->dest_vn_name() == "vn1"); + + DelLink("virtual-machine-interface", input1[0].name, + "subnet", "subnet"); + client->WaitForIdle(); + DeleteVmportEnv(input1, 1, true, 1); + client->WaitForIdle(); + WAIT_FOR(500, 1000, RouteFind("vrf1", "8.1.1.2", 32) == false); + + EXPECT_FALSE(VmPortFind(8)); + VmInterfaceKey key(AgentKey::ADD_DEL_CHANGE, MakeUuid(8), ""); + WAIT_FOR(100, 1000, (Agent::GetInstance()->interface_table()->Find(&key, true) + == NULL)); + client->Reset(); +} + +//Verify that ARP route gets updated with policy +//when interface policy changes +TEST_F(ArpTest, SubnetResolveWithPolicyUpdate) { + struct PortInfo input1[] = { + {"vnet8", 8, "8.1.1.1", "00:00:00:01:01:01", 1, 1} + }; + + client->Reset(); + //Create VM interface with policy + CreateVmportWithEcmp(input1, 1); + client->WaitForIdle(); + EXPECT_TRUE(VmPortActive(input1, 0)); + EXPECT_TRUE(VmPortFind(8)); + client->Reset(); + + //Add a link to interface subnet and ensure resolve route is added + AddSubnetType("subnet", 1, "8.1.1.0", 24); + AddLink("virtual-machine-interface", input1[0].name, + "subnet", "subnet"); + client->WaitForIdle(); + EXPECT_TRUE(VmPortActive(input1, 0)); + EXPECT_TRUE(RouteFind("vrf1", "8.1.1.0", 24)); + + Ip4Address sip = Ip4Address::from_string("8.1.1.1"); + Ip4Address dip = Ip4Address::from_string("8.1.1.2"); + VmInterface *vintf = VmInterfaceGet(8); + SendArpReq(vintf->id(), vintf->vrf()->vrf_id(), sip.to_ulong(), dip.to_ulong()); + client->WaitForIdle(); + WAIT_FOR(500, 1000, RouteFind("vrf1", "8.1.1.2", 32) == true); + + AgentRoute *rt = RouteGet("vrf1", dip, 32); + EXPECT_TRUE(rt->GetActiveNextHop()->GetType() == NextHop::ARP); + const ArpNH *arp_nh = static_cast(rt->GetActiveNextHop()); + EXPECT_TRUE(arp_nh->GetInterface() == vintf); + EXPECT_TRUE(arp_nh->PolicyEnabled() == false); + EXPECT_TRUE(rt->GetActivePath()->dest_vn_name() == "vn1"); + + SendArpReply(vintf->id(), vintf->vrf()->vrf_id(), + sip.to_ulong(), dip.to_ulong()); + client->WaitForIdle(); + WAIT_FOR(500, 1000, arp_nh->GetResolveState() == true); + EXPECT_TRUE(arp_nh->PolicyEnabled() == false); + + //Change policy of interface + AddAcl("acl1", 1); + AddLink("virtual-network", "vn1", "access-control-list", "acl1"); + client->WaitForIdle(); + arp_nh = static_cast(rt->GetActiveNextHop()); + EXPECT_TRUE(arp_nh->PolicyEnabled() == true); + + DelLink("virtual-machine-interface", input1[0].name, + "subnet", "subnet"); + client->WaitForIdle(); + WAIT_FOR(500, 1000, RouteFind("vrf1", "8.1.1.2", 32) == false); + + DelAcl("acl1"); + DelLink("virtual-network", "vn1", "access-control-list", "acl1"); + DeleteVmportEnv(input1, 1, true); + client->WaitForIdle(); + WAIT_FOR(500, 1000, RouteFind("vrf1", "8.1.1.2", 32) == false); + + EXPECT_FALSE(VmPortFind(8)); + VmInterfaceKey key(AgentKey::ADD_DEL_CHANGE, MakeUuid(8), ""); + WAIT_FOR(100, 1000, (Agent::GetInstance()->interface_table()->Find(&key, true) + == NULL)); + client->Reset(); +} + +//Test to check update on resolve route, would result +//in arp routes also getting updated +TEST_F(ArpTest, SubnetResolveWithSg) { + struct PortInfo input1[] = { + {"vnet8", 8, "8.1.1.1", "00:00:00:01:01:01", 1, 1} + }; + + client->Reset(); + //Create VM interface with policy + CreateVmportWithEcmp(input1, 1, 1); + client->WaitForIdle(); + EXPECT_TRUE(VmPortActive(input1, 0)); + EXPECT_TRUE(VmPortFind(8)); + client->Reset(); + + AddSg("sg1", 1); + AddAcl("acl1", 1); + AddLink("security-group", "sg1", "access-control-list", "acl1"); + client->WaitForIdle(); + AddLink("virtual-machine-interface", "vnet8", "security-group", "sg1"); + //Add a link to interface subnet and ensure resolve route is added + AddSubnetType("subnet", 1, "8.1.1.0", 24); + AddLink("virtual-machine-interface", input1[0].name, + "subnet", "subnet"); + client->WaitForIdle(); + EXPECT_TRUE(VmPortActive(input1, 0)); + EXPECT_TRUE(RouteFind("vrf1", "8.1.1.0", 24)); + + Ip4Address sip = Ip4Address::from_string("8.1.1.1"); + Ip4Address dip = Ip4Address::from_string("8.1.1.2"); + VmInterface *vintf = VmInterfaceGet(8); + SendArpReq(vintf->id(), vintf->vrf()->vrf_id(), sip.to_ulong(), dip.to_ulong()); + client->WaitForIdle(); + WAIT_FOR(500, 1000, RouteFind("vrf1", "8.1.1.2", 32) == true); + + AgentRoute *rt = RouteGet("vrf1", dip, 32); + EXPECT_TRUE(rt->GetActiveNextHop()->GetType() == NextHop::ARP); + const ArpNH *arp_nh = static_cast(rt->GetActiveNextHop()); + EXPECT_TRUE(arp_nh->GetInterface() == vintf); + EXPECT_TRUE(arp_nh->PolicyEnabled() == true); + EXPECT_TRUE(rt->GetActivePath()->dest_vn_name() == "vn1"); + EXPECT_TRUE(rt->GetActivePath()->sg_list().size() == 1); + + DelLink("virtual-machine-interface", input1[0].name, + "subnet", "subnet"); + DelLink("security-group", "sg1", "access-control-list", "acl1"); + DelAcl("acl1"); + DelNode("security-group", "sg1"); + client->WaitForIdle(); + DeleteVmportEnv(input1, 1, true, 1); + client->WaitForIdle(); + WAIT_FOR(500, 1000, RouteFind("vrf1", "8.1.1.2", 32) == false); + + EXPECT_FALSE(VmPortFind(8)); + VmInterfaceKey key(AgentKey::ADD_DEL_CHANGE, MakeUuid(8), ""); + WAIT_FOR(100, 1000, (Agent::GetInstance()->interface_table()->Find(&key, true) + == NULL)); + client->Reset(); +} + +TEST_F(ArpTest, IntfArpReqTest_1) { + struct PortInfo input[] = { + {"vnet1", 1, "1.1.1.1", "00:00:00:01:01:01", 1, 1}, + }; + + //Create VM, VN, VRF and Vmport + CreateVmportEnv(input, 1); + client->WaitForIdle(); + EXPECT_TRUE(VmPortActive(input, 0)); + Interface *itf = VmPortGet(1); + VmInterface *vmi = static_cast(itf); + VrfEntry *vrf = VrfGet("vrf1"); + + Agent::GetInstance()->GetArpProto()->ClearInterfaceArpStats(vmi->id()); + Ip4Address arp_tip = Ip4Address::from_string("1.1.1.2"); + EXPECT_EQ(1U, Agent::GetInstance()->GetArpProto()->GetArpCacheSize()); // For GW + SendArpReq(vmi->id(), vrf->vrf_id(), vmi->ip_addr().to_ulong(), arp_tip.to_ulong()); + WaitForCompletion(2); + EXPECT_TRUE(FindArpNHEntry(arp_tip.to_ulong(), "vrf1")); + WAIT_FOR(500, 1000, (Agent::GetInstance()->GetArpProto()->ArpRequestStatsCounter(vmi->id()) >= 1U)); + + DeleteVmportEnv(input, 1, true); + client->WaitForIdle(); +} + +TEST_F(ArpTest, IntfArpReqTest_2) { + struct PortInfo input[] = { + {"vnet1", 1, "1.1.1.1", "00:00:00:01:01:01", 1, 1}, + }; + //Create VM, VN, VRF and Vmport + CreateVmportEnv(input, 1); + client->WaitForIdle(); + EXPECT_TRUE(VmPortActive(input, 0)); + Interface *itf = VmPortGet(1); + VmInterface *vmi = static_cast(itf); + VrfEntry *vrf = VrfGet("vrf1"); + + Agent::GetInstance()->GetArpProto()->ClearInterfaceArpStats(vmi->id()); + Ip4Address arp_tip = Ip4Address::from_string("1.1.1.2"); + EXPECT_EQ(1U, Agent::GetInstance()->GetArpProto()->GetArpCacheSize()); // For GW + SendArpReq(vmi->id(), vrf->vrf_id(), vmi->ip_addr().to_ulong(), arp_tip.to_ulong()); + WaitForCompletion(2); + EXPECT_TRUE(FindArpNHEntry(arp_tip.to_ulong(), "vrf1")); + EXPECT_TRUE(FindArpRoute(arp_tip.to_ulong(), "vrf1")); + WAIT_FOR(500, 1000, (Agent::GetInstance()->GetArpProto()->ArpRequestStatsCounter(vmi->id()) >= 1U)); + SendArpReply(vmi->id(), vrf->vrf_id(), vmi->ip_addr().to_ulong(), arp_tip.to_ulong()); + client->WaitForIdle(); + WAIT_FOR(500, 1000, (1U == Agent::GetInstance()->GetArpProto()->ArpReplyStatsCounter(vmi->id()))); + WAIT_FOR(500, 1000, (1U == Agent::GetInstance()->GetArpProto()->ArpResolvedStatsCounter(vmi->id()))); + DeleteVmportEnv(input, 1, true); + client->WaitForIdle(); +} void RouterIdDepInit(Agent *agent) { } diff --git a/src/vnsw/agent/services/test/dhcp_test.cc b/src/vnsw/agent/services/test/dhcp_test.cc index 6f87a2b977c..d584b0f776a 100644 --- a/src/vnsw/agent/services/test/dhcp_test.cc +++ b/src/vnsw/agent/services/test/dhcp_test.cc @@ -28,6 +28,7 @@ #include #include "vr_types.h" +#define MAC_LEN 6 #define CLIENT_REQ_IP "1.2.3.4" #define CLIENT_REQ_PREFIX "1.2.3.0" #define CLIENT_REQ_GW "1.2.3.1" @@ -1314,6 +1315,109 @@ TEST_F(DhcpTest, PortSpecificDhcpOptions) { Agent::GetInstance()->GetDhcpProto()->ClearStats(); } +// Check that DHCP requests from TOR are served +TEST_F(DhcpTest, DhcpTorRequestTest) { + struct PortInfo input[] = { + {"vnet1", 1, "1.1.1.1", "00:00:00:01:01:01", 1, 1}, + {"vnet2", 2, "1.1.1.2", "00:00:00:02:02:02", 1, 2}, + }; + uint8_t options[] = { + DHCP_OPTION_MSG_TYPE, + DHCP_OPTION_HOST_NAME, + DHCP_OPTION_DOMAIN_NAME, + DHCP_OPTION_END + }; + DhcpProto::DhcpStats stats; + + ClearPktTrace(); + IpamInfo ipam_info[] = { + {"1.2.3.128", 27, "1.2.3.129", true}, + {"7.8.9.0", 24, "7.8.9.12", true}, + {"1.1.1.0", 24, "1.1.1.200", true}, + }; + char vdns_attr[] = "\n test.contrail.juniper.net\n true\n fixed\n 120\n \n"; + char ipam_attr[] = "\n virtual-dns-server\n vdns1\n \n"; + + CreateVmportEnv(input, 2, 0); + client->WaitForIdle(); + client->Reset(); + AddVDNS("vdns1", vdns_attr); + client->WaitForIdle(); + AddIPAM("vn1", ipam_info, 3, ipam_attr, "vdns1"); + client->WaitForIdle(); + + // use the mac address of the VM as the source MAC + char mac1[MAC_LEN] = { 0x00, 0x00, 0x00, 0x01, 0x01, 0x01 }; + src_mac = MacAddress(mac1); + + SendDhcp(fabric_interface_id(), 0x8000, DHCP_DISCOVER, options, 4); + SendDhcp(fabric_interface_id(), 0x8000, DHCP_REQUEST, options, 4); + int count = 0; + DHCP_CHECK (stats.acks < 1); + EXPECT_EQ(1U, stats.discover); + EXPECT_EQ(1U, stats.request); + EXPECT_EQ(1U, stats.offers); + EXPECT_EQ(1U, stats.acks); + + char mac2[MAC_LEN] = { 0x00, 0x00, 0x00, 0x02, 0x02, 0x02 }; + src_mac = MacAddress(mac2); + + SendDhcp(fabric_interface_id(), 0x8000, DHCP_DISCOVER, options, 4); + SendDhcp(fabric_interface_id(), 0x8000, DHCP_REQUEST, options, 4); + count = 0; + DHCP_CHECK (stats.acks < 2); + EXPECT_EQ(2U, stats.discover); + EXPECT_EQ(2U, stats.request); + EXPECT_EQ(2U, stats.offers); + EXPECT_EQ(2U, stats.acks); + + SendDhcp(fabric_interface_id(), 0x8000, DHCP_INFORM, options, 4); + SendDhcp(fabric_interface_id(), 0x8000, DHCP_DECLINE, options, 4); + count = 0; + DHCP_CHECK (stats.decline < 1); + EXPECT_EQ(2U, stats.discover); + EXPECT_EQ(2U, stats.request); + EXPECT_EQ(1U, stats.inform); + EXPECT_EQ(1U, stats.decline); + EXPECT_EQ(2U, stats.offers); + EXPECT_EQ(3U, stats.acks); + + char mac3[MAC_LEN] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }; + src_mac = MacAddress(mac3); + + SendDhcp(fabric_interface_id(), 0x8000, DHCP_DISCOVER, options, 4, true); + count = 0; + DHCP_CHECK (stats.errors < 1); + EXPECT_EQ(2U, stats.discover); + EXPECT_EQ(2U, stats.request); + EXPECT_EQ(1U, stats.inform); + EXPECT_EQ(1U, stats.decline); + EXPECT_EQ(2U, stats.offers); + EXPECT_EQ(3U, stats.acks); + EXPECT_EQ(1U, stats.errors); + client->WaitForIdle(); + + DhcpInfo *sand = new DhcpInfo(); + Sandesh::set_response_callback( + boost::bind(&DhcpTest::CheckSandeshResponse, this, _1, + true, "", DHCP_RESPONSE_STRING, false, "", true)); + sand->HandleRequest(); + client->WaitForIdle(); + sand->Release(); + + client->Reset(); + DelIPAM("vn1", "vdns1"); + client->WaitForIdle(); + DelVDNS("vdns1"); + client->WaitForIdle(); + + client->Reset(); + DeleteVmportEnv(input, 2, 1, 0); + client->WaitForIdle(); + + Agent::GetInstance()->GetDhcpProto()->ClearStats(); +} + TEST_F(DhcpTest, DhcpEnableTestForward) { DhcpEnableTest(true); } diff --git a/src/vnsw/agent/services/test/metadata_test.cc b/src/vnsw/agent/services/test/metadata_test.cc index a4deddc8d01..42d38d39233 100644 --- a/src/vnsw/agent/services/test/metadata_test.cc +++ b/src/vnsw/agent/services/test/metadata_test.cc @@ -24,6 +24,7 @@ #include #include #include +#include "pkt/test/test_pkt_util.h" #define MAX_WAIT_COUNT 5000 #define BUF_SIZE 8192 @@ -67,6 +68,7 @@ class MetadataTest : public ::testing::Test { }; void SetUp() { + agent_ = Agent::GetInstance(); } void TearDown() { @@ -126,8 +128,8 @@ class MetadataTest : public ::testing::Test { global_config << "\n" << "\n" << "metadata\n" - << "\n" - << "0\n" + << "169.254.169.254\n" + << "80\n" << "\n" << "" << nova_api_proxy_->GetPort() @@ -306,6 +308,7 @@ class MetadataTest : public ::testing::Test { delete request; } + Agent *agent_; private: HttpServer *nova_api_proxy_; HttpClient *vm_http_client_; @@ -331,6 +334,22 @@ TEST_F(MetadataTest, MetadataReqTest) { client->WaitForIdle(); client->Reset(); + VmInterface *intf = static_cast(VmPortGet(1)); + TxTcpPacket(intf->id(), vm1_ip, "169.254.169.254", 1000, 80, false); + client->WaitForIdle(); + FlowEntry *flow = FlowGet(0, vm1_ip, "169.254.169.254", 6, 1000, 80, + intf->flow_key_nh()->id()); + EXPECT_TRUE(flow != NULL); + FlowEntry *rflow = flow->reverse_flow_entry(); + EXPECT_TRUE(rflow != NULL); + + EXPECT_TRUE(flow->key().src_addr.to_v4() == + Ip4Address::from_string(vm1_ip)); + EXPECT_TRUE(flow->key().dst_addr.to_v4() == + Ip4Address::from_string("169.254.169.254")); + EXPECT_TRUE(rflow->key().src_addr.to_v4() == agent_->router_id()); + EXPECT_TRUE(rflow->key().dst_addr.to_v4() == intf->mdata_ip_addr()); + StartHttpClient(); // If the local address is not same as VM address in this request, @@ -375,6 +394,69 @@ TEST_F(MetadataTest, MetadataReqTest) { Agent::GetInstance()->services()->metadataproxy()->ClearStats(); } +TEST_F(MetadataTest, MetadataReqTest_services_ip) { + int count = 0; + MetadataProxy::MetadataStats stats; + struct PortInfo input[] = { + {"vnet1", 1, vm1_ip, "00:00:00:01:01:01", 1, 1}, + }; + + // Change compute_node_ip + Ip4Address old_ip = agent_->compute_node_ip(); + AgentParam param(agent_); + param.BuildAddressList("5.5.5.5"); + TestAgentInit *init = static_cast(client->agent_init()); + init->ProcessComputeAddress(¶m); + + StartNovaApiProxy(); + SetupLinkLocalConfig(); + + CreateVmportEnv(input, 1, 0); + client->WaitForIdle(); + client->Reset(); + + StartHttpClient(); + + // If the local address is not same as VM address in this request, + // agent will have an internal error as it cannot find the VM + HttpConnection *conn = SendHttpClientRequest(GET_METHOD); + METADATA_CHECK (stats.internal_errors < 1); + EXPECT_EQ(1U, stats.requests); + EXPECT_EQ(0U, stats.responses); + EXPECT_EQ(0U, stats.proxy_sessions); + CloseClientSession(conn); + client->WaitForIdle(); + + VmInterface *intf = static_cast(VmPortGet(1)); + TxTcpPacket(intf->id(), vm1_ip, "169.254.169.254", 1000, 80, false); + client->WaitForIdle(); + FlowEntry *flow = FlowGet(0, vm1_ip, "169.254.169.254", 6, 1000, 80, + intf->flow_key_nh()->id()); + EXPECT_TRUE(flow != NULL); + FlowEntry *rflow = flow->reverse_flow_entry(); + EXPECT_TRUE(rflow != NULL); + + EXPECT_TRUE(flow->key().src_addr.to_v4() == + Ip4Address::from_string(vm1_ip)); + EXPECT_TRUE(flow->key().dst_addr.to_v4() == + Ip4Address::from_string("169.254.169.254")); + + EXPECT_TRUE(rflow->key().src_addr.to_v4() == + Ip4Address::from_string("5.5.5.5")); + EXPECT_TRUE(rflow->key().dst_addr.to_v4() == intf->mdata_ip_addr()); + client->Reset(); + StopHttpClient(); + DeleteVmportEnv(input, 1, 1, 0); + client->WaitForIdle(); + + ClearLinkLocalConfig(); + StopNovaApiProxy(); + client->WaitForIdle(); + agent_->set_compute_node_ip(old_ip); + + Agent::GetInstance()->services()->metadataproxy()->ClearStats(); +} + // Send PUT / POST / HEAD / DELETE requests TEST_F(MetadataTest, MetadataOtherMethodsTest) { int count = 0; @@ -492,7 +574,6 @@ TEST_F(MetadataTest, MetadataNoLinkLocalTest) { // Send message and close server connection while message is going TEST_F(MetadataTest, MetadataCloseServerTest) { - int count = 0; MetadataProxy::MetadataStats stats; struct PortInfo input[] = { {"vnet1", 1, vm1_ip, "00:00:00:01:01:01", 1, 1}, @@ -514,7 +595,6 @@ TEST_F(MetadataTest, MetadataCloseServerTest) { for (int i = 0; i < 200; i++) { large_data.append("add more data to be sent"); } - HttpConnection *conn = SendHttpClientRequest(POST_METHOD, large_data); // stop server StopNovaApiProxy(); client->WaitForIdle(); diff --git a/src/vnsw/agent/test-xml/test_xml.cc b/src/vnsw/agent/test-xml/test_xml.cc index 06e67a85f0e..2e9e53fe010 100644 --- a/src/vnsw/agent/test-xml/test_xml.cc +++ b/src/vnsw/agent/test-xml/test_xml.cc @@ -86,6 +86,9 @@ void LinkXmlNode(xml_node *parent, const string <ype, const string lname, n2 = n1.append_child("name"); n2.append_child(pugi::node_pcdata).set_value(rname.c_str()); + string mdata = ltype + "-" + rtype; + xml_node n3 = n.append_child("metadata"); + n3.append_attribute("type") = mdata.c_str(); return; } @@ -137,6 +140,10 @@ void AgentUtXmlTest::AddValidateEntry(const std::string &name, AgentUtXmlTest::AgentUtXmlTestConfigCreateFn AgentUtXmlTest::GetConfigCreateFn(const std::string &name) { AgentUtXmlTestConfigFactory::iterator iter = config_factory_.find(name); + if (iter == config_factory_.end()) { + return AgentUtXmlTest::AgentUtXmlTestConfigCreateFn(); + } + return iter->second; } @@ -575,7 +582,6 @@ bool AgentUtXmlPacket::ReadXml() { GetStringAttribute(node(), "tunnel_dip", &tunnel_dip_); GetUintAttribute(node(), "label", (uint16_t *)&label_); - uint16_t id = 0; if (GetUintAttribute(node(), "id", &intf_id_) == false) { cout << "Attribute \"id\" not specified for Packet. Skipping" << endl; diff --git a/src/vnsw/agent/test-xml/test_xml_oper.cc b/src/vnsw/agent/test-xml/test_xml_oper.cc index f929f7151b2..061965b040a 100644 --- a/src/vnsw/agent/test-xml/test_xml_oper.cc +++ b/src/vnsw/agent/test-xml/test_xml_oper.cc @@ -773,7 +773,6 @@ AgentUtXmlFlowValidate::~AgentUtXmlFlowValidate() { } bool AgentUtXmlFlowValidate::ReadXml() { - uint16_t id = 0; if (GetUintAttribute(node(), "nh", &nh_id_) == false) { cout << "Attribute \"nh\" not specified for Flow. Skipping" << endl; return false; diff --git a/src/vnsw/agent/test/agent.gdb b/src/vnsw/agent/test/agent.gdb index f20ade6a473..fe8b25c71f3 100644 --- a/src/vnsw/agent/test/agent.gdb +++ b/src/vnsw/agent/test/agent.gdb @@ -269,7 +269,7 @@ define pksync_entries help pksync_entries else # set the node equal to first node and end marker - set $Xtree = &((RouteKSyncObject *)$arg0)->tree_.tree_ + set $Xtree = &((KSyncDBObject *)$arg0)->tree_.tree_ set $Xnode = $Xtree->data_.node_plus_pred_.header_plus_size_.header_.left_ set $Xend = &($Xtree->data_.node_plus_pred_.header_plus_size_.header_) diff --git a/src/vnsw/agent/test/test_agent_init.cc b/src/vnsw/agent/test/test_agent_init.cc index 46309126bf0..a739c3d2729 100644 --- a/src/vnsw/agent/test/test_agent_init.cc +++ b/src/vnsw/agent/test/test_agent_init.cc @@ -47,6 +47,10 @@ void TestAgentInit::ProcessOptions } } +void TestAgentInit::ProcessComputeAddress(AgentParam *param) { + ContrailInitCommon::ProcessComputeAddress(param); +} + /**************************************************************************** * Initialization routines ***************************************************************************/ diff --git a/src/vnsw/agent/test/test_agent_init.h b/src/vnsw/agent/test/test_agent_init.h index 18d2c6329c0..1f1c4c28110 100644 --- a/src/vnsw/agent/test/test_agent_init.h +++ b/src/vnsw/agent/test/test_agent_init.h @@ -32,6 +32,7 @@ class TestAgentInit : public ContrailInitCommon { void WaitForIdle(); TestPkt0Interface *pkt0() const { return pkt0_.get(); } + void ProcessComputeAddress(AgentParam *param); private: std::auto_ptr ksync_; std::auto_ptr uve_; diff --git a/src/vnsw/agent/test/test_agent_route_walker.cc b/src/vnsw/agent/test/test_agent_route_walker.cc index 0b83936f6f7..27fb6bca305 100644 --- a/src/vnsw/agent/test/test_agent_route_walker.cc +++ b/src/vnsw/agent/test/test_agent_route_walker.cc @@ -78,8 +78,12 @@ class AgentRouteWalkerTest : public AgentRouteWalker, public ::testing::Test { if (num_vrfs > 2) { VrfAddReq(vrf_name_3_.c_str()); } + InetInterfaceKey vhost_intf_key( + Agent::GetInstance()->vhost_interface()->name()); Agent::GetInstance()->fabric_inet4_unicast_table()->AddResolveRoute( - Agent::GetInstance()->fabric_vrf_name(), server_ip_, 24); + Agent::GetInstance()->local_peer(), + Agent::GetInstance()->fabric_vrf_name(), server_ip_, 24, + vhost_intf_key, 0, false, "", SecurityGroupList()); client->WaitForIdle(); client->WaitForIdle(); if (num_vrfs > 0) { diff --git a/src/vnsw/agent/test/test_cmn_util.h b/src/vnsw/agent/test/test_cmn_util.h index 1b0b3e2cd6c..8ef280dbb40 100644 --- a/src/vnsw/agent/test/test_cmn_util.h +++ b/src/vnsw/agent/test/test_cmn_util.h @@ -299,6 +299,7 @@ void DelVmPortVrf(const char *name); uint32_t PathCount(const string vrf_name, const Ip4Address &addr, int plen); bool VlanNhFind(int id, uint16_t tag); void AddInstanceIp(const char *name, int id, const char* addr); +void AddSubnetType(const char *name, int id, const char* addr, uint8_t); void AddActiveActiveInstanceIp(const char *name, int id, const char* addr); void DelInstanceIp(const char *name); extern Peer *bgp_peer_; diff --git a/src/vnsw/agent/test/test_fip_cfg.cc b/src/vnsw/agent/test/test_fip_cfg.cc index ebd755ef4e4..b05ec15cafd 100644 --- a/src/vnsw/agent/test/test_fip_cfg.cc +++ b/src/vnsw/agent/test/test_fip_cfg.cc @@ -187,7 +187,8 @@ TEST_F(CfgTest, FloatingIp_1) { PhysicalInterface::CreateReq(Agent::GetInstance()->interface_table(), "enet1", Agent::GetInstance()->fabric_vrf_name(), - PhysicalInterface::FABRIC); + PhysicalInterface::FABRIC, + PhysicalInterface::ETHERNET, false); client->WaitForIdle(); AddArp("10.1.1.2", "00:00:00:00:00:02", "enet1"); diff --git a/src/vnsw/agent/test/test_l2route.cc b/src/vnsw/agent/test/test_l2route.cc index 8ed70995e70..996275c6ac0 100644 --- a/src/vnsw/agent/test/test_l2route.cc +++ b/src/vnsw/agent/test/test_l2route.cc @@ -84,7 +84,8 @@ class RouteTest : public ::testing::Test { PhysicalInterface::CreateReq(agent_->interface_table(), eth_name_, agent_->fabric_vrf_name(), - PhysicalInterface::FABRIC); + PhysicalInterface::FABRIC, + PhysicalInterface::ETHERNET, false); AddResolveRoute(server1_ip_, 24); client->WaitForIdle(); } @@ -118,8 +119,11 @@ class RouteTest : public ::testing::Test { } void AddResolveRoute(const Ip4Address &server_ip, uint32_t plen) { + InetInterfaceKey vhost_key(agent_->vhost_interface()->name()); agent_->fabric_inet4_unicast_table()->AddResolveRoute( - agent_->fabric_vrf_name(), server_ip, plen); + agent_->local_peer(), + agent_->fabric_vrf_name(), server_ip, plen, vhost_key, + 0, false, "", SecurityGroupList()); client->WaitForIdle(); } diff --git a/src/vnsw/agent/test/test_mirror.cc b/src/vnsw/agent/test/test_mirror.cc index cda26b5c9e0..dd67d636050 100644 --- a/src/vnsw/agent/test/test_mirror.cc +++ b/src/vnsw/agent/test/test_mirror.cc @@ -42,7 +42,8 @@ class MirrorTableTest : public ::testing::Test { nh_count_ = agent_->nexthop_table()->Size(); PhysicalInterface::CreateReq(agent_->interface_table(), eth_itf, agent_->fabric_vrf_name(), - PhysicalInterface::FABRIC); + PhysicalInterface::FABRIC, + PhysicalInterface::ETHERNET, false); fabric_gw_ip_ = Ip4Address::from_string("10.1.1.254"); uint16_t sport = 10000; unsigned long ip = 0x0a010102; diff --git a/src/vnsw/agent/test/test_nh.cc b/src/vnsw/agent/test/test_nh.cc index f59031ecd20..44498fd62df 100644 --- a/src/vnsw/agent/test/test_nh.cc +++ b/src/vnsw/agent/test/test_nh.cc @@ -370,7 +370,7 @@ TEST_F(CfgTest, EcmpNH_2) { {"vnet5", 5, "1.1.1.1", "00:00:00:02:02:05", 1, 5} }; - CreateVmportWithEcmp(input1, 1); + CreateVmportWithEcmp(input1, 1, 1); client->WaitForIdle(); //First VM added, route points to composite NH Ip4Address ip = Ip4Address::from_string("1.1.1.1"); @@ -378,6 +378,7 @@ TEST_F(CfgTest, EcmpNH_2) { EXPECT_TRUE(rt != NULL); const NextHop *nh = rt->GetActiveNextHop(); EXPECT_TRUE(nh->GetType() == NextHop::INTERFACE); + EXPECT_TRUE(nh->PolicyEnabled() == true); //Second VM added, route should point to composite NH CreateVmportWithEcmp(input2, 1); @@ -386,6 +387,7 @@ TEST_F(CfgTest, EcmpNH_2) { EXPECT_TRUE(nh->GetType() == NextHop::COMPOSITE); const CompositeNH *comp_nh = static_cast(nh); EXPECT_TRUE(comp_nh->ComponentNHCount() == 2); + EXPECT_TRUE(comp_nh->Get(0)->nh()->PolicyEnabled() == false); CreateVmportWithEcmp(input3, 1); client->WaitForIdle(); @@ -1914,11 +1916,13 @@ TEST_F(CfgTest, Nexthop_keys) { vrf_nh->SetKey(vrf_nh_key); DoNextHopSandesh(); + InetInterfaceKey vhost_intf_key(agent_->vhost_interface()->name()); //Tunnel NH key agent_-> fabric_inet4_unicast_table()-> - AddResolveRoute(agent_->fabric_vrf_name(), - Ip4Address::from_string("10.1.1.100"), 32); + AddResolveRoute(agent_->local_peer(), agent_->fabric_vrf_name(), + Ip4Address::from_string("10.1.1.100"), 32, + vhost_intf_key, 0, false, "", SecurityGroupList()); client->WaitForIdle(); MacAddress remote_vm_mac("00:00:01:01:01:11"); @@ -2018,14 +2022,16 @@ TEST_F(CfgTest, Nexthop_keys) { //ARP NH with vm interface DBRequest arp_nh_req; arp_nh_req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; - arp_nh_req.key.reset(new ArpNHKey("vrf10", Ip4Address::from_string("11.11.11.11"))); + arp_nh_req.key.reset(new ArpNHKey("vrf10", Ip4Address::from_string("11.11.11.11"), + false)); MacAddress intf_vm_mac("00:00:01:01:01:11"); VmInterfaceKey *intf_key = new VmInterfaceKey(AgentKey::ADD_DEL_CHANGE, MakeUuid(10), "vrf10"); arp_nh_req.data.reset(new ArpNHData(intf_vm_mac, intf_key, true)); agent_->nexthop_table()->Enqueue(&arp_nh_req); client->WaitForIdle(); - ArpNHKey find_arp_nh_key("vrf10", Ip4Address::from_string("11.11.11.11")); + ArpNHKey find_arp_nh_key("vrf10", Ip4Address::from_string("11.11.11.11"), + false); ArpNH *arp_nh = static_cast (agent_->nexthop_table()->FindActiveEntry(&find_arp_nh_key)); EXPECT_TRUE(arp_nh != NULL); @@ -2035,11 +2041,13 @@ TEST_F(CfgTest, Nexthop_keys) { DBRequest del_arp_nh_req; del_arp_nh_req.oper = DBRequest::DB_ENTRY_DELETE; - del_arp_nh_req.key.reset(new ArpNHKey("vrf10", Ip4Address::from_string("11.11.11.11"))); - del_arp_nh_req.data.reset(new ArpNHData()); + del_arp_nh_req.key.reset(new ArpNHKey("vrf10", Ip4Address::from_string("11.11.11.11"), + false)); + del_arp_nh_req.data.reset(NULL); agent_->nexthop_table()->Enqueue(&del_arp_nh_req); client->WaitForIdle(); - ArpNHKey find_del_arp_nh_key("vrf10", Ip4Address::from_string("11.11.11.11")); + ArpNHKey find_del_arp_nh_key("vrf10", Ip4Address::from_string("11.11.11.11"), + false); EXPECT_TRUE(agent_->nexthop_table()-> FindActiveEntry(&find_del_arp_nh_key) == NULL); @@ -2061,14 +2069,17 @@ TEST_F(CfgTest, Nexthop_invalid_vrf) { client->WaitForIdle(); client->Reset(); + InetInterfaceKey vhost_intf_key(agent_->vhost_interface()->name()); //ARP NH DBRequest arp_nh_req; arp_nh_req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; - arp_nh_req.key.reset(new ArpNHKey("vrf11", Ip4Address::from_string("11.11.11.11"))); - arp_nh_req.data.reset(new ArpNHData()); + arp_nh_req.key.reset(new ArpNHKey("vrf11", Ip4Address::from_string("11.11.11.11"), + false)); + arp_nh_req.data.reset(new ArpNHData(&vhost_intf_key)); agent_->nexthop_table()->Enqueue(&arp_nh_req); client->WaitForIdle(); - ArpNHKey find_arp_nh_key("vrf11", Ip4Address::from_string("11.11.11.11")); + ArpNHKey find_arp_nh_key("vrf11", Ip4Address::from_string("11.11.11.11"), + false); EXPECT_TRUE(agent_->nexthop_table()-> FindActiveEntry(&find_arp_nh_key) == NULL); diff --git a/src/vnsw/agent/test/test_route.cc b/src/vnsw/agent/test/test_route.cc index 692c2f968be..050301c9897 100644 --- a/src/vnsw/agent/test/test_route.cc +++ b/src/vnsw/agent/test/test_route.cc @@ -103,7 +103,8 @@ class RouteTest : public ::testing::Test { PhysicalInterface::CreateReq(Agent::GetInstance()->interface_table(), eth_name_, Agent::GetInstance()->fabric_vrf_name(), - PhysicalInterface::FABRIC); + PhysicalInterface::FABRIC, + PhysicalInterface::ETHERNET, false); AddResolveRoute(server1_ip_, 24); client->WaitForIdle(); @@ -161,8 +162,12 @@ class RouteTest : public ::testing::Test { } void AddResolveRoute(const Ip4Address &server_ip, uint32_t plen) { + InetInterfaceKey vhost_intf_key( + Agent::GetInstance()->vhost_interface()->name()); Agent::GetInstance()->fabric_inet4_unicast_table()->AddResolveRoute( - Agent::GetInstance()->fabric_vrf_name(), server_ip, plen); + Agent::GetInstance()->local_peer(), + Agent::GetInstance()->fabric_vrf_name(), server_ip, plen, + vhost_intf_key, 0, false, "", SecurityGroupList()); client->WaitForIdle(); } @@ -170,7 +175,9 @@ class RouteTest : public ::testing::Test { const Ip4Address &ip, int plen, const Ip4Address &server) { Agent::GetInstance()->fabric_inet4_unicast_table()->AddGatewayRouteReq - (vrf_name, ip, plen, server, ""); + (Agent::GetInstance()->local_peer(), + vrf_name, ip, plen, server, "", MplsTable::kInvalidLabel, + SecurityGroupList()); client->WaitForIdle(); } @@ -959,7 +966,7 @@ class TestNhState : public DBState { class TestNhPeer : public Peer { public: - TestNhPeer() : Peer(BGP_PEER, "TestNH"), dummy_(0) { }; + TestNhPeer() : Peer(BGP_PEER, "TestNH", false), dummy_(0) { }; int dummy_; }; @@ -1498,7 +1505,7 @@ TEST_F(RouteTest, PathPreference_1) { CreateVmportEnv(input, 1); client->WaitForIdle(); - Peer peer(Peer::LOCAL_VM_PORT_PEER, "test_peer"); + Peer peer(Peer::LOCAL_VM_PORT_PEER, "test_peer", true); Ip4Address ip = Ip4Address::from_string("1.1.1.10"); //Enqueue path change for non existent path DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE); diff --git a/src/vnsw/agent/test/test_scale_walk.cc b/src/vnsw/agent/test/test_scale_walk.cc index 4e8266bae40..9a2c5b9dc4a 100644 --- a/src/vnsw/agent/test/test_scale_walk.cc +++ b/src/vnsw/agent/test/test_scale_walk.cc @@ -41,7 +41,7 @@ TEST_F(AgentBasicScaleTest, Basic) { BuildVmPortEnvironment(); //Create a walker and pass callback - Peer *dummy_peer = new Peer(Peer::BGP_PEER, "dummy_peer"); + Peer *dummy_peer = new Peer(Peer::BGP_PEER, "dummy_peer", false); ControllerRouteWalkerTest *route_walker_test = new ControllerRouteWalkerTest(dummy_peer); SetWalkerYield(walker_yield); @@ -82,7 +82,7 @@ TEST_F(AgentBasicScaleTest, local_and_remote) { (total_v4_routes + num_remote))); //Create a walker and pass callback - Peer *dummy_peer = new Peer(Peer::BGP_PEER, "dummy_peer"); + Peer *dummy_peer = new Peer(Peer::BGP_PEER, "dummy_peer", false); ControllerRouteWalkerTest *route_walker_test = new ControllerRouteWalkerTest(dummy_peer); SetWalkerYield(walker_yield); diff --git a/src/vnsw/agent/test/test_tunnel_encap.cc b/src/vnsw/agent/test/test_tunnel_encap.cc index 8b7026909d1..e705874749c 100644 --- a/src/vnsw/agent/test/test_tunnel_encap.cc +++ b/src/vnsw/agent/test/test_tunnel_encap.cc @@ -113,9 +113,13 @@ class TunnelEncapTest : public ::testing::Test { } void AddResolveRoute(const Ip4Address &server_ip, uint32_t plen) { + InetInterfaceKey vhost_intf_key( + Agent::GetInstance()->vhost_interface()->name()); Agent::GetInstance()-> fabric_inet4_unicast_table()->AddResolveRoute( - Agent::GetInstance()->fabric_vrf_name(), server_ip, plen); + Agent::GetInstance()->local_peer(), + Agent::GetInstance()->fabric_vrf_name(), server_ip, plen, + vhost_intf_key, 0, false, "", SecurityGroupList()); client->WaitForIdle(); } diff --git a/src/vnsw/agent/test/test_util.cc b/src/vnsw/agent/test/test_util.cc index 08b08d4ad51..826d6ad9ecd 100644 --- a/src/vnsw/agent/test/test_util.cc +++ b/src/vnsw/agent/test/test_util.cc @@ -180,6 +180,7 @@ void AddNodeString(char *buff, int &len, const char *nodename, const char *name, str << " " << ipam[i].plen << "\n"; str << " \n"; str << " " << ipam[i].gw << "\n"; + str << " " << ipam[i].gw << "\n"; str << " " << dhcp_enable << "\n"; if (add_subnet_tags) str << add_subnet_tags << "\n"; @@ -424,7 +425,7 @@ VrfEntry *VrfGet(const char *name, bool ret_del) { VrfKey key(name); VrfEntry *vrf = static_cast(agent->vrf_table()->Find(&key, ret_del)); - if (ret_del == false && vrf->IsDeleted()) + if (vrf && (ret_del == false && vrf->IsDeleted())) vrf = NULL; return vrf; @@ -643,10 +644,10 @@ bool VrfStatsMatch(int vrf_id, std::string vrf_name, bool stats_match, st->udp_mpls_tunnels == udp_mpls_tunnels && st->gre_mpls_tunnels == gre_mpls_tunnels && st->ecmp_composites == ecmp_composites && - st->l3_mcast_composites == l3_mcast_composites && + //st->l3_mcast_composites == l3_mcast_composites && st->l2_mcast_composites == l2_mcast_composites && st->fabric_composites == fabric_composites && - st->multi_proto_composites == multi_proto_composites && + //st->multi_proto_composites == multi_proto_composites && st->l2_encaps == l2_encaps && st->encaps == encaps) { return true; } @@ -683,10 +684,10 @@ bool VrfStatsMatchPrev(int vrf_id, uint64_t discards, uint64_t resolves, st->prev_udp_mpls_tunnels == udp_mpls_tunnels && st->prev_gre_mpls_tunnels == gre_mpls_tunnels && st->prev_ecmp_composites == ecmp_composites && - st->prev_l3_mcast_composites == l3_mcast_composites && + //st->prev_l3_mcast_composites == l3_mcast_composites && st->prev_l2_mcast_composites == l2_mcast_composites && st->prev_fabric_composites == fabric_composites && - st->prev_multi_proto_composites == multi_proto_composites && + //st->prev_multi_proto_composites == multi_proto_composites && st->prev_l2_encaps == l2_encaps && st->prev_encaps == encaps) { return true; } @@ -1267,9 +1268,10 @@ bool AddArp(const char *ip, const char *mac_str, const char *ifname) { intf = static_cast(Agent::GetInstance()->interface_table()->FindActiveEntry(&key)); boost::system::error_code ec; InetUnicastAgentRouteTable::ArpRoute(DBRequest::DB_ENTRY_ADD_CHANGE, + Agent::GetInstance()->fabric_vrf_name(), Ip4Address::from_string(ip, ec), mac, Agent::GetInstance()->fabric_vrf_name(), - *intf, true, 32); + *intf, true, 32, false, "", SecurityGroupList()); return true; } @@ -1281,8 +1283,10 @@ bool DelArp(const string &ip, const char *mac_str, const string &ifname) { intf = static_cast(Agent::GetInstance()->interface_table()->FindActiveEntry(&key)); boost::system::error_code ec; InetUnicastAgentRouteTable::ArpRoute(DBRequest::DB_ENTRY_DELETE, + Agent::GetInstance()->fabric_vrf_name(), Ip4Address::from_string(ip, ec), - mac, Agent::GetInstance()->fabric_vrf_name(), *intf, false, 32); + mac, Agent::GetInstance()->fabric_vrf_name(), *intf, + false, 32, false, "", SecurityGroupList()); return true; } @@ -1341,10 +1345,17 @@ void DelVn(const char *name) { } void AddPort(const char *name, int id, const char *attr) { - if (attr) - AddNode("virtual-machine-interface", name, id, attr); - else - AddNode("virtual-machine-interface", name, id); + std::stringstream str; + str << "" << endl; + str << " 00:00:00:00:00:" << id << "" + << endl; + str << "" << endl; + + char buff[1028]; + strcpy(buff, str.str().c_str()); + if (attr != NULL) + strcat(buff, attr); + AddNode("virtual-machine-interface", name, id, buff); } void AddPortByStatus(const char *name, int id, bool admin_status) { @@ -1558,6 +1569,16 @@ void DelInstanceIp(const char *name) { DelNode("instance-ip", name); } +void AddSubnetType(const char *name, int id, const char *addr, uint8_t plen) { + + char buf[1024]; + sprintf(buf, "\n" + "%s\n" + "%d\n" + "", addr, plen); + AddNode("subnet", name, id, buf); +} + void AddVmPortVrf(const char *name, const string &ip, uint16_t tag) { char buff[256]; int len = 0; @@ -2910,7 +2931,7 @@ void DeleteBgpPeer(Peer *peer) { void FillEvpnNextHop(BgpPeer *peer, std::string vrf_name, uint32_t label, uint32_t bmap) { TunnelOlist evpn_olist_map; - evpn_olist_map.push_back(OlistTunnelEntry(label, + evpn_olist_map.push_back(OlistTunnelEntry(nil_uuid(), label, IpAddress::from_string("8.8.8.8").to_v4(), bmap)); MulticastHandler::ModifyEvpnMembers(peer, vrf_name, diff --git a/src/vnsw/agent/test/test_vmport_cfg.cc b/src/vnsw/agent/test/test_vmport_cfg.cc index 6fd078a6a3d..02eaa2cefb0 100644 --- a/src/vnsw/agent/test/test_vmport_cfg.cc +++ b/src/vnsw/agent/test/test_vmport_cfg.cc @@ -1198,7 +1198,8 @@ TEST_F(CfgTest, Basic_1) { client->Reset(); PhysicalInterface::CreateReq(Agent::GetInstance()->interface_table(), - eth_intf, vrf_name, PhysicalInterface::FABRIC); + eth_intf, vrf_name, PhysicalInterface::FABRIC, + PhysicalInterface::ETHERNET, false); client->WaitForIdle(); phy_intf = static_cast (agent_->interface_table()->FindActiveEntry(&key)); @@ -1206,7 +1207,8 @@ TEST_F(CfgTest, Basic_1) { PhysicalInterface::CreateReq(Agent::GetInstance()->interface_table(), eth_intf, Agent::GetInstance()->fabric_vrf_name(), - PhysicalInterface::FABRIC); + PhysicalInterface::FABRIC, + PhysicalInterface::ETHERNET, false); client->WaitForIdle(); phy_intf = static_cast diff --git a/src/vnsw/agent/test/test_xmpp_discovery.cc b/src/vnsw/agent/test/test_xmpp_discovery.cc index 6e8d1bcb446..fd300dc2e65 100644 --- a/src/vnsw/agent/test/test_xmpp_discovery.cc +++ b/src/vnsw/agent/test/test_xmpp_discovery.cc @@ -254,7 +254,8 @@ TEST_F(AgentXmppUnitTest, XmppConnection_Discovery) { client->WaitForIdle(); //wait for connection establishment - EXPECT_TRUE(agent_->controller_ifmap_xmpp_port(0) == xs1->GetPort()); + EXPECT_TRUE(agent_->controller_ifmap_xmpp_port(0) == + (uint32_t)xs1->GetPort()); WAIT_FOR(1000, 10000, agent_->controller_xmpp_channel(0)->GetXmppChannel()->GetPeerState() == xmps::READY); @@ -276,7 +277,8 @@ TEST_F(AgentXmppUnitTest, XmppConnection_Discovery) { client->WaitForIdle(); //wait for connection establishment - EXPECT_TRUE(agent_->controller_ifmap_xmpp_port(1) == xs2->GetPort()); + EXPECT_TRUE(agent_->controller_ifmap_xmpp_port(1) == + (uint32_t)xs2->GetPort()); WAIT_FOR(1000, 10000, agent_->controller_xmpp_channel(1)->GetXmppChannel()->GetPeerState() == xmps::READY); @@ -298,7 +300,8 @@ TEST_F(AgentXmppUnitTest, XmppConnection_Discovery) { client->WaitForIdle(); //wait for connection establishment - EXPECT_TRUE(agent_->controller_ifmap_xmpp_port(0) == xs3->GetPort()); + EXPECT_TRUE(agent_->controller_ifmap_xmpp_port(0) == + (uint32_t)xs3->GetPort()); WAIT_FOR(1000, 10000, agent_->controller_xmpp_channel(0)->GetXmppChannel()->GetPeerState() == xmps::READY); @@ -318,12 +321,14 @@ TEST_F(AgentXmppUnitTest, XmppConnection_Discovery) { client->WaitForIdle(); //wait for connection establishment - EXPECT_TRUE(agent_->controller_ifmap_xmpp_port(0) == xs3->GetPort()); + EXPECT_TRUE(agent_->controller_ifmap_xmpp_port(0) == + (uint32_t)xs3->GetPort()); WAIT_FOR(1000, 10000, agent_->controller_xmpp_channel(0)->GetXmppChannel()->GetPeerState() == xmps::READY); - EXPECT_TRUE(agent_->controller_ifmap_xmpp_port(1) == xs4->GetPort()); + EXPECT_TRUE(agent_->controller_ifmap_xmpp_port(1) == + (uint32_t)xs4->GetPort()); WAIT_FOR(1000, 10000, agent_->controller_xmpp_channel(1)->GetXmppChannel()->GetPeerState() == xmps::READY); @@ -349,12 +354,14 @@ TEST_F(AgentXmppUnitTest, XmppConnection_Discovery) { client->WaitForIdle(); //wait for connection establishment - EXPECT_TRUE(agent_->controller_ifmap_xmpp_port(0) == xs5->GetPort()); + EXPECT_TRUE(agent_->controller_ifmap_xmpp_port(0) == + (uint32_t)xs5->GetPort()); WAIT_FOR(1000, 10000, agent_->controller_xmpp_channel(0)->GetXmppChannel()->GetPeerState() == xmps::READY); - EXPECT_TRUE(agent_->controller_ifmap_xmpp_port(1) == xs6->GetPort()); + EXPECT_TRUE(agent_->controller_ifmap_xmpp_port(1) == + (uint32_t)xs6->GetPort()); WAIT_FOR(1000, 10000, agent_->controller_xmpp_channel(1)->GetXmppChannel()->GetPeerState() == xmps::READY); diff --git a/src/vnsw/agent/uve/agent_stats_sandesh_context.cc b/src/vnsw/agent/uve/agent_stats_sandesh_context.cc index 0228b231a84..a0018010346 100644 --- a/src/vnsw/agent/uve/agent_stats_sandesh_context.cc +++ b/src/vnsw/agent/uve/agent_stats_sandesh_context.cc @@ -118,7 +118,7 @@ void AgentStatsSandeshContext::VrfStatsMsgHandler(vr_vrf_stats_req *req) { stats->prev_ecmp_composites; stats->l2_mcast_composites = req->get_vsr_l2_mcast_composites() - stats->prev_l2_mcast_composites; - stats->fabric_composites = req->get_vsr_fabric_composites() - + stats->fabric_composites = req->get_vsr_fabric_composites() - stats->prev_fabric_composites; /* Update the last read values from Kernel in the following fields. diff --git a/src/vnsw/agent/uve/agent_uve_base.cc b/src/vnsw/agent/uve/agent_uve_base.cc index f0c1e34b191..4f62207ef57 100644 --- a/src/vnsw/agent/uve/agent_uve_base.cc +++ b/src/vnsw/agent/uve/agent_uve_base.cc @@ -78,7 +78,7 @@ uint8_t AgentUveBase::ExpectedConnections(uint8_t &num_control_nodes, num_control_nodes++; count++; } - if (!agent_->dns_server(i).empty()) { + if (agent_->services() && !agent_->dns_server(i).empty()) { num_dns_servers++; count++; } diff --git a/src/vnsw/agent/uve/test/test_vm_uve.cc b/src/vnsw/agent/uve/test/test_vm_uve.cc index af480bf3952..f7064d8d72c 100644 --- a/src/vnsw/agent/uve/test/test_vm_uve.cc +++ b/src/vnsw/agent/uve/test/test_vm_uve.cc @@ -636,7 +636,7 @@ TEST_F(UveVmUveTest, FipL3Disabled) { AddLink("virtual-machine-interface-routing-instance", "vnet1", "virtual-machine-interface", "vnet1"); client->WaitForIdle(3); - EXPECT_TRUE(VmPortInactive(input, 0)); + EXPECT_TRUE(VmPortActive(input, 0)); //Create a VN for floating-ip client->Reset(); diff --git a/src/vnsw/agent/uve/test/test_vn_uve.cc b/src/vnsw/agent/uve/test/test_vn_uve.cc index 3aa64dbb543..8ab11090644 100644 --- a/src/vnsw/agent/uve/test/test_vn_uve.cc +++ b/src/vnsw/agent/uve/test/test_vn_uve.cc @@ -101,9 +101,8 @@ class UveVnUveTest : public ::testing::Test { client->Reset(); DeleteVmportEnv(input, 2, true, 1); client->WaitForIdle(3); - client->PortDelNotifyWait(2); - EXPECT_FALSE(VmPortFind(input, 0)); - EXPECT_FALSE(VmPortFind(input, 1)); + WAIT_FOR(1000, 1000, (VmPortFind(input, 0) == false)); + WAIT_FOR(1000, 1000, (VmPortFind(input, 1) == false)); EXPECT_EQ(0U, Agent::GetInstance()->pkt()->flow_table()->Size()); } @@ -479,7 +478,7 @@ TEST_F(UveVnUveTest, FlowCount_1) { EXPECT_EQ(4U, uve1->get_egress_flow_count()); DeleteFlow(flow, 1); - EXPECT_EQ(2U, Agent::GetInstance()->pkt()->flow_table()->Size()); + WAIT_FOR(1000, 1000, (Agent::GetInstance()->pkt()->flow_table()->Size() == 2U)); vnut->SendVnStats(false); EXPECT_EQ(2U, uve1->get_ingress_flow_count()); EXPECT_EQ(2U, uve1->get_egress_flow_count()); @@ -549,7 +548,8 @@ TEST_F(UveVnUveTest, FlowCount_2) { //Delete a flow DeleteFlow(flow, 1); - EXPECT_EQ(2U, Agent::GetInstance()->pkt()->flow_table()->Size()); + WAIT_FOR(1000, 1000, + (2U == Agent::GetInstance()->pkt()->flow_table()->Size())); //Trigger VN UVE send vnut->SendVnStats(false); diff --git a/src/vnsw/agent/uve/vn_uve_table_base.cc b/src/vnsw/agent/uve/vn_uve_table_base.cc index 586dac34ee4..890b1e843f7 100644 --- a/src/vnsw/agent/uve/vn_uve_table_base.cc +++ b/src/vnsw/agent/uve/vn_uve_table_base.cc @@ -156,7 +156,8 @@ void VnUveTableBase::InterfaceAddHandler(const VmEntry* vm, const VnEntry* vn, UveVirtualNetworkAgent uve; - vn_uve_entry->VmAdd(vm->GetCfgName()); + if (vm) + vn_uve_entry->VmAdd(vm->GetCfgName()); vn_uve_entry->InterfaceAdd(intf); if (vn_uve_entry->BuildInterfaceVmList(uve)) { DispatchVnMsg(uve); @@ -189,15 +190,16 @@ void VnUveTableBase::InterfaceNotify(DBTablePartBase *partition, DBEntryBase *e) } else { const VmEntry *vm = vm_port->vm(); const VnEntry *vn = vm_port->vn(); + std::string vm_name = vm? vm->GetCfgName() : agent_->NullString(); if (!state) { - state = new VnUveInterfaceState(vm->GetCfgName(), + state = new VnUveInterfaceState(vm_name, vn->GetName(), false, false); e->SetState(partition->parent(), intf_listener_id_, state); } /* Change in VM config name is not supported now */ if (state->vm_name_ != agent_->NullString() && - (state->vm_name_.compare(vm->GetCfgName()) != 0)) { + (state->vm_name_.compare(vm_name) != 0)) { assert(0); } /* Change in VN name is not supported now */ diff --git a/src/vnsw/agent/uve/vrouter_uve_entry_base.cc b/src/vnsw/agent/uve/vrouter_uve_entry_base.cc index 22e0028b162..3426fbdf421 100644 --- a/src/vnsw/agent/uve/vrouter_uve_entry_base.cc +++ b/src/vnsw/agent/uve/vrouter_uve_entry_base.cc @@ -56,7 +56,7 @@ void VrouterUveEntryBase::DispatchVrouterMsg(const VrouterAgent &uve) { void VrouterUveEntryBase::VmWalkDone(DBTableBase *base, StringVectorPtr list) { VrouterAgent vrouter_agent; - vrouter_agent.set_name(agent_->host_name()); + vrouter_agent.set_name(agent_->agent_name()); vrouter_agent.set_virtual_machine_list(*(list.get())); DispatchVrouterMsg(vrouter_agent); } @@ -106,7 +106,7 @@ void VrouterUveEntryBase::VmNotify(DBTablePartBase *partition, DBEntryBase *e) { void VrouterUveEntryBase::VnWalkDone(DBTableBase *base, StringVectorPtr list) { VrouterAgent vrouter_agent; - vrouter_agent.set_name(agent_->host_name()); + vrouter_agent.set_name(agent_->agent_name()); vrouter_agent.set_connected_networks(*(list.get())); DispatchVrouterMsg(vrouter_agent); } @@ -156,7 +156,7 @@ void VrouterUveEntryBase::InterfaceWalkDone(DBTableBase *base, StringVectorPtr err_if_list, StringVectorPtr nova_if_list) { VrouterAgent vrouter_agent; - vrouter_agent.set_name(agent_->host_name()); + vrouter_agent.set_name(agent_->agent_name()); vrouter_agent.set_interface_list(*(if_list.get())); vrouter_agent.set_error_intf_list(*(err_if_list.get())); vrouter_agent.set_no_config_intf_list(*(nova_if_list.get())); @@ -366,7 +366,7 @@ void VrouterUveEntryBase::SendVrouterUve() { VrouterAgent vrouter_agent; bool changed = false; static bool first = true, build_info = false; - vrouter_agent.set_name(agent_->host_name()); + vrouter_agent.set_name(agent_->agent_name()); Ip4Address rid = agent_->router_id(); vector ip_list; vector dns_list; diff --git a/src/vnsw/agent/vxlan_agent/linux/linux_vxlan_agent_init.cc b/src/vnsw/agent/vxlan_agent/linux/linux_vxlan_agent_init.cc index b11d54ec621..8d7e8fb7ac1 100644 --- a/src/vnsw/agent/vxlan_agent/linux/linux_vxlan_agent_init.cc +++ b/src/vnsw/agent/vxlan_agent/linux/linux_vxlan_agent_init.cc @@ -75,10 +75,12 @@ void LinuxVxlanAgentInit::CreateModules() { void LinuxVxlanAgentInit::RegisterDBClients() { ksync_vxlan_->RegisterDBClients(agent()->db()); + uve_->RegisterDBClients(); } void LinuxVxlanAgentInit::InitModules() { ksync_vxlan_->Init(); + uve_->Init(); } void LinuxVxlanAgentInit::ConnectToController() {