Line data Source code
1 : /* 2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. 3 : * Copyright Contributors to the OpenSDN project 4 : */ 5 : 6 : #ifndef SRC_BGP_ROUTING_INSTANCE_RTARGET_GROUP_MGR_H_ 7 : #define SRC_BGP_ROUTING_INSTANCE_RTARGET_GROUP_MGR_H_ 8 : 9 : #include <boost/ptr_container/ptr_map.hpp> 10 : #include <boost/shared_ptr.hpp> 11 : #include <sandesh/sandesh_types.h> 12 : #include <sandesh/sandesh.h> 13 : #include <sandesh/sandesh_trace.h> 14 : 15 : #include <map> 16 : #include <set> 17 : #include <string> 18 : #include <vector> 19 : #include <mutex> 20 : 21 : #include "base/queue_task.h" 22 : #include "base/lifetime.h" 23 : #include "bgp/community.h" 24 : #include "bgp/routing-instance/rtarget_group.h" 25 : #include "bgp/rtarget/rtarget_address.h" 26 : #include "db/db_table_partition.h" 27 : 28 : class BgpRoute; 29 : class BgpServer; 30 : class BgpTable; 31 : class RibOut; 32 : class RibPeerSet; 33 : class RTargetRoute; 34 : class RTargetGroupMgr; 35 : class TaskTrigger; 36 : 37 : // 38 : // This keeps track of the RTargetGroupMgr's listener state for a BgpTable. 39 : // The BgpTable could be a VPN table or bgp.rtarget.0. 40 : // 41 : class RtGroupMgrTableState { 42 : public: 43 : RtGroupMgrTableState(BgpTable *table, DBTableBase::ListenerId id); 44 : ~RtGroupMgrTableState(); 45 : 46 : void ManagedDelete(); 47 : 48 816541 : DBTableBase::ListenerId GetListenerId() const { 49 816541 : return id_; 50 : } 51 : 52 : private: 53 : DBTableBase::ListenerId id_; 54 : LifetimeRef<RtGroupMgrTableState> table_delete_ref_; 55 : 56 : DISALLOW_COPY_AND_ASSIGN(RtGroupMgrTableState); 57 : }; 58 : 59 : // 60 : // The RTargetGroupMgr sets VPNRouteState on dependent VPN BgpRoutes. This 61 : // VPNRouteState is simply a list of the current RouteTargets that we have 62 : // seen and processed for the BgpRoute. When the RouteTargets for a BgpRoute 63 : // get updated, the VPNRouteState is used to update the appropriate RtGroups 64 : // list of dependent VPN routes. 65 : // 66 : class VpnRouteState : public DBState { 67 : public: 68 : typedef std::set<RouteTarget> RTargetList; 69 : 70 : void AddRouteTarget(RTargetGroupMgr *mgr, int part_id, BgpRoute *rt, 71 : RTargetList::const_iterator it); 72 : void DeleteRouteTarget(RTargetGroupMgr *mgr, int part_id, BgpRoute *rt, 73 : RTargetList::const_iterator it); 74 : 75 : private: 76 : friend class RTargetGroupMgr; 77 : 78 617355 : const RTargetList *GetList() const { return &list_; } 79 617496 : RTargetList *GetMutableList() { return &list_; } 80 : 81 : RTargetList list_; 82 : }; 83 : 84 : // 85 : // The RTargetGroupMgr sets RTargetState on RTargetRoutes. This RTargetState 86 : // is the current InterestedPeerList that we have seen and processed for the 87 : // RTargetRoute. When a BgpPath is added or deleted for a RTargetRoute the 88 : // RTargetState is used to update the appropriate RtGroups InterestedPeerList. 89 : // 90 : class RTargetState : public DBState { 91 : public: 92 : void AddInterestedPeer(RTargetGroupMgr *mgr, RtGroup *rtgroup, 93 : RTargetRoute *rt, RtGroup::InterestedPeerList::const_iterator it); 94 : void DeleteInterestedPeer(RTargetGroupMgr *mgr, RtGroup *rtgroup, 95 : RTargetRoute *rt, RtGroup::InterestedPeerList::iterator it); 96 : 97 : private: 98 : friend class RTargetGroupMgr; 99 : 100 102664 : const RtGroup::InterestedPeerList *GetList() const { return &list_; } 101 102664 : RtGroup::InterestedPeerList *GetMutableList() { return &list_; } 102 : 103 : RtGroup::InterestedPeerList list_; 104 : }; 105 : 106 : struct RtGroupMgrReq { 107 : enum RequestType { 108 : SHOW_RTGROUP, 109 : SHOW_RTGROUP_PEER, 110 : SHOW_RTGROUP_SUMMARY, 111 : }; 112 : 113 : RtGroupMgrReq(RequestType type, SandeshResponse *resp, 114 : const std::string ¶m = std::string()) 115 : : type_(type), snh_resp_(resp), param_(param) { 116 : } 117 : 118 : RequestType type_; 119 : SandeshResponse *snh_resp_; 120 : std::string param_; 121 : 122 : private: 123 : DISALLOW_COPY_AND_ASSIGN(RtGroupMgrReq); 124 : }; 125 : 126 : // 127 : // This class implements the core logic required to construct and update the 128 : // policy for RouteTarget based constrained distribution of BGP VPN routes. 129 : // This policy is applied when exporting BgpRoutes from VPN tables such as 130 : // bgp.l3vpn.0 and bgp.evpn.0. 131 : // 132 : // The RtGroupMap keeps track of all RtGroups using a map of RouteTarget to 133 : // RtGroup pointers. A RtGroup is created the first time it's needed. There 134 : // are 3 possible triggers: 135 : // 136 : // 1. RoutePathReplicator needs to associate BgpTables with the RouteTarget. 137 : // 2. A VPN BgpRoute with the RouteTarget as one of it's targets is received. 138 : // 3. A RTargetRoute for the RouteTarget is received. 139 : // 140 : // The users of RtGroups invoke RemoveRtGroup when they no longer need it. If 141 : // the RtGroup is eligible to be deleted i.e. it has no state associated with 142 : // it, it gets added to the RtGroupRemoveList. The list is processed in the 143 : // context of the bgp::RTFilter task. The RtGroup is deleted if it's still 144 : // eligible for deletion i.e. it hasn't been resurrected after being enqueued. 145 : // Processing RtGroup deletion in this manner avoids race conditions wherein 146 : // one db::DBTable task deletes an RtGroup while another db::DBTable task has 147 : // a pointer to it. 148 : // 149 : // A mutex is used to protect the RtGroupMap since LocateRtGroup/GetRtGroup 150 : // is called from multiple db::DBTable tasks concurrently. The same mutex is 151 : // also used to protect the RtGroupRemoveList as multiple db::DBTable tasks 152 : // can try to add RtGroups to the list concurrently. 153 : // 154 : // The RTargetGroupMgr needs to register as a listener for all VPN tables and 155 : // for bgp.rtarget.0. It keeps track of it's listener ids for the tables using 156 : // the RtGroupMgrTableStateList. Note that it does not need to register for 157 : // any VRF tables, only for the VPN tables in the master routing instance and 158 : // bgp.rtarget.0 (which also belongs to the master instance). 159 : // 160 : // The RTargetGroupMgr registers as a listener for all VPN tables so that it 161 : // can maintain the list of the dependent VPN routes for a given RouteTarget. 162 : // The actual dependency is maintained in the associated RtGroup object based 163 : // on APIs invoked from the RTargetGroupMgr. 164 : // 165 : // The RTargetGroupMgr sets VPNRouteState on dependent VPN BgpRoutes. This 166 : // VPNRouteState is simply a list of the current RouteTargets that we have 167 : // seen and processed for the BgpRoute. When the RouteTargets for a BgpRoute 168 : // get updated, the VPNRouteState is used to update the appropriate RtGroups 169 : // list of dependent VPN routes. 170 : // 171 : // The VPNRouteState and the list of dependent VPN BgpRoutes are updated from 172 : // the context of the db::DBTable task i.e. when processing notification for a 173 : // VPN BgpRoute. 174 : // 175 : // The RTargetGroupMgr also registers as a listener for bgp.rtarget.0 so that 176 : // it can maintain the list of interested peers for a given RouteTarget. The 177 : // actual dependency is maintained in the associated RtGroup object based on 178 : // APIs invoked from the RTargetGroupMgr. 179 : // 180 : // The RTargetGroupMgr sets RTargetState on RTargetRoutes. This RTargetState 181 : // is the current InterestedPeerList that we have seen and processed for the 182 : // RTargetRoute. When a BgpPath is added or deleted for a RTargetRoute the 183 : // RTargetState is used to update the appropriate RtGroups InterestedPeerList. 184 : // 185 : // The RTargetState and the InterestedPeerList are not updated directly from 186 : // the context of the db::DBTable task. Instead, the RTargetRoute is added 187 : // to the RTargetRouteTriggerList. The RTargetRouteTriggerList keeps track of 188 : // RTargetRoutes that need to be processed and is evaluated from context of 189 : // bgp::RTFilter task. This lets us absorb multiple changes to a RTargetRoute 190 : // in one shot. Since the bgp::RTFilter task is mutually exclusive with the 191 : // db::DBTable task, this also prevents any concurrency issues wherein the 192 : // BgpExport::Export method for the VPN tables accesses the InterestedPeerList 193 : // for an RtGroups while it's being modified on account of changes to the 194 : // RTargetRoute. 195 : // 196 : // When a RTargetRoute in the RTargetRouteTriggerList is processed, we figure 197 : // out if InterestedPeerList has changed. If so, the RouteTarget in question 198 : // is added to all the RouteTargetTriggerLists, one per DBTable partition. The 199 : // RouteTargetTriggerList keeps track of RouteTargets whose dependent BgpRoutes 200 : // need to be re-evaluated. It gets processed in the context of db::DBTable 201 : // task. All RouteTargetTriggerLists can be processed concurrently since they 202 : // work on different partitions. As db::DBTable tasks are mutually exclusive 203 : // with the bgp::RTFilter task, it is guaranteed that a RouteTargetTriggerList 204 : // does not get modified while it's being processed. 205 : // 206 : class RTargetGroupMgr { 207 : public: 208 : typedef boost::ptr_map<const RouteTarget, RtGroup> RtGroupMap; 209 : typedef RtGroupMap::const_iterator const_iterator; 210 : 211 : explicit RTargetGroupMgr(BgpServer *server); 212 : virtual ~RTargetGroupMgr(); 213 : 214 41140 : bool empty() const { return rtgroup_map_.empty(); } 215 : const_iterator begin() const { return rtgroup_map_.begin(); } 216 4598 : const_iterator end() const { return rtgroup_map_.end(); } 217 502 : const_iterator lower_bound(const RouteTarget &rt) const { 218 502 : return rtgroup_map_.lower_bound(rt); 219 : } 220 : 221 : // RtGroup 222 : RtGroup *GetRtGroup(const RouteTarget &rt); 223 : RtGroup *GetRtGroup(const ExtCommunity::ExtCommunityValue &comm); 224 : RtGroup *LocateRtGroup(const RouteTarget &rt); 225 : void NotifyRtGroupUnlocked(const RouteTarget &rt); 226 : void NotifyRtGroup(const RouteTarget &rt); 227 : void RemoveRtGroup(const RouteTarget &rt); 228 : 229 : virtual void GetRibOutInterestedPeers(RibOut *ribout, 230 : const ExtCommunity *ext_community, 231 : const RibPeerSet &peerset, RibPeerSet *new_peerset); 232 : void Enqueue(RtGroupMgrReq *req); 233 : void Initialize(); 234 : void ManagedDelete(); 235 1543764 : bool IsRTargetRoutesProcessed() const { 236 1543764 : return rtarget_route_list_.empty(); 237 : } 238 : 239 : private: 240 : friend class BgpXmppRTargetTest; 241 : friend class ReplicationTest; 242 : 243 : typedef std::map<BgpTable *, 244 : RtGroupMgrTableState *> RtGroupMgrTableStateList; 245 : typedef std::set<RTargetRoute *> RTargetRouteTriggerList; 246 : typedef std::set<RouteTarget> RouteTargetTriggerList; 247 : typedef std::set<RtGroup *> RtGroupRemoveList; 248 : 249 : void RTargetDepSync(DBTablePartBase *root, BgpRoute *rt, 250 : DBTableBase::ListenerId id, VpnRouteState *dbstate, 251 : const VpnRouteState::RTargetList *future); 252 : void RTargetPeerSync(BgpTable *table, RTargetRoute *rt, 253 : DBTableBase::ListenerId id, RTargetState *dbstate, 254 : const RtGroup::InterestedPeerList *future); 255 : void BuildRTargetDistributionGraph(BgpTable *table, RTargetRoute *rt, 256 : DBTableBase::ListenerId id); 257 58898 : BgpServer *server() { return server_; } 258 : 259 : bool ProcessRTargetRouteList(); 260 : void DisableRTargetRouteProcessing(); 261 : void EnableRTargetRouteProcessing(); 262 : bool IsRTargetRouteOnList(RTargetRoute *rt) const; 263 : 264 : bool ProcessRouteTargetList(int part_id); 265 : void AddRouteTargetToLists(const RouteTarget &rtarget); 266 : void DisableRouteTargetProcessing(); 267 : void EnableRouteTargetProcessing(); 268 : bool IsRouteTargetOnList(const RouteTarget &rtarget) const; 269 : 270 : bool ProcessRtGroupList(); 271 : void DisableRtGroupProcessing(); 272 : void EnableRtGroupProcessing(); 273 : bool IsRtGroupOnList(RtGroup *rtgroup) const; 274 : 275 : DBTableBase::ListenerId GetListenerId(BgpTable *table); 276 : void UnregisterTables(); 277 : bool VpnRouteNotify(DBTablePartBase *root, DBEntryBase *entry); 278 : bool RTargetRouteNotify(DBTablePartBase *root, DBEntryBase *entry); 279 : bool RequestHandler(RtGroupMgrReq *req); 280 : 281 : BgpServer *server_; 282 : std::mutex mutex_; 283 : RtGroupMap rtgroup_map_; 284 : RtGroupMgrTableStateList table_state_; 285 : boost::scoped_ptr<TaskTrigger> rtarget_route_trigger_; 286 : boost::scoped_ptr<TaskTrigger> remove_rtgroup_trigger_; 287 : std::vector<boost::shared_ptr<TaskTrigger> > rtarget_dep_triggers_; 288 : RTargetRouteTriggerList rtarget_route_list_; 289 : std::vector<RouteTargetTriggerList> rtarget_trigger_lists_; 290 : RtGroupRemoveList rtgroup_remove_list_; 291 : LifetimeRef<RTargetGroupMgr> master_instance_delete_ref_; 292 : 293 : DISALLOW_COPY_AND_ASSIGN(RTargetGroupMgr); 294 : }; 295 : 296 : #endif // SRC_BGP_ROUTING_INSTANCE_RTARGET_GROUP_MGR_H_