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