Line data Source code
1 : /*
2 : * Copyright (c) 2016 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 : #include "bgp/bgp_xmpp_rtarget_manager.h"
6 :
7 : #include <utility>
8 : #include <vector>
9 :
10 : #include <boost/foreach.hpp>
11 :
12 : #include "bgp/ipeer.h"
13 : #include "bgp/bgp_peer_types.h"
14 : #include "bgp/bgp_server.h"
15 : #include "bgp/bgp_xmpp_channel.h"
16 : #include "routing-instance/routing_instance.h"
17 :
18 : using std::make_pair;
19 : using std::pair;
20 : using std::string;
21 : using std::vector;
22 :
23 10060 : BgpXmppRTargetManager::BgpXmppRTargetManager(BgpXmppChannel *bgp_xmpp_channel) :
24 10060 : bgp_xmpp_channel_(bgp_xmpp_channel) {
25 10060 : }
26 :
27 20102 : BgpXmppRTargetManager::~BgpXmppRTargetManager() {
28 20102 : }
29 :
30 15939 : bool BgpXmppRTargetManager::IsSubscriptionEmpty() const {
31 15939 : return bgp_xmpp_channel_->IsSubscriptionEmpty();
32 : }
33 :
34 7790 : bool BgpXmppRTargetManager::IsSubscriptionGrStale(
35 : RoutingInstance *instance) const {
36 7790 : return bgp_xmpp_channel_->IsSubscriptionGrStale(instance);
37 : }
38 :
39 7790 : bool BgpXmppRTargetManager::IsSubscriptionLlgrStale(
40 : RoutingInstance *instance) const {
41 7790 : return bgp_xmpp_channel_->IsSubscriptionLlgrStale(instance);
42 : }
43 :
44 42219 : bool BgpXmppRTargetManager::delete_in_progress() const {
45 42219 : return bgp_xmpp_channel_->delete_in_progress();
46 : }
47 :
48 78931 : const IPeer *BgpXmppRTargetManager::Peer() const {
49 78931 : return bgp_xmpp_channel_->Peer();
50 : }
51 :
52 78931 : void BgpXmppRTargetManager::Enqueue(DBRequest *req) const {
53 : RoutingInstanceMgr *instance_mgr =
54 78931 : bgp_xmpp_channel_->bgp_server()->routing_instance_mgr();
55 78931 : RoutingInstance *master = instance_mgr->GetDefaultRoutingInstance();
56 78931 : BgpTable *table = master->GetTable(Address::RTARGET);
57 78929 : assert(table);
58 78929 : table->Enqueue(req);
59 78931 : }
60 :
61 60397 : BgpAttrPtr BgpXmppRTargetManager::GetRouteTargetRouteAttr() const {
62 60397 : BgpAttrSpec attrs;
63 60398 : BgpAttrNextHop nexthop(bgp_xmpp_channel_->bgp_server()->bgp_identifier());
64 60398 : attrs.push_back(&nexthop);
65 60397 : BgpAttrOrigin origin(BgpAttrOrigin::IGP);
66 60397 : attrs.push_back(&origin);
67 120797 : return bgp_xmpp_channel_->bgp_server()->attr_db()->Locate(attrs);
68 60399 : }
69 :
70 74261 : int BgpXmppRTargetManager::local_autonomous_system() const {
71 74261 : return bgp_xmpp_channel_->bgp_server()->local_autonomous_system();
72 : }
73 :
74 : const BgpXmppRTargetManager::RouteTargetList &
75 14880 : BgpXmppRTargetManager::GetSubscribedRTargets(RoutingInstance *instance) const {
76 14880 : return bgp_xmpp_channel_->GetSubscribedRTargets(instance);
77 : }
78 :
79 38050 : uint32_t BgpXmppRTargetManager::GetRTargetRouteFlag(
80 : const RouteTarget &rtarget) const {
81 : PublishedRTargetRoutes::const_iterator rt_loc =
82 38050 : rtarget_routes_.find(rtarget);
83 38050 : if (rt_loc == rtarget_routes_.end() || rt_loc->second.empty())
84 31019 : return 0;
85 :
86 : // Route is [llgr-]stale only if it is stale for all instances in the set.
87 7031 : uint32_t flags = BgpPath::Stale | BgpPath::LlgrStale;
88 15716 : BOOST_FOREACH(RoutingInstance *routing_instance, rt_loc->second) {
89 7850 : if (!IsSubscriptionGrStale(routing_instance))
90 7015 : flags &= ~BgpPath::Stale;
91 7850 : if (!IsSubscriptionLlgrStale(routing_instance))
92 7830 : flags &= ~BgpPath::LlgrStale;
93 7850 : if (!flags)
94 7015 : break;
95 : }
96 :
97 7031 : return flags;
98 : }
99 :
100 79039 : void BgpXmppRTargetManager::RTargetRouteOp(as_t asn,
101 : const RouteTarget &rtarget,
102 : BgpAttrPtr attr, bool add_change,
103 : uint32_t flags) const {
104 79039 : if (add_change && delete_in_progress())
105 0 : return;
106 :
107 79039 : DBRequest req;
108 79039 : RTargetPrefix rt_prefix(asn, rtarget);
109 79039 : req.key.reset(new RTargetTable::RequestKey(rt_prefix, Peer()));
110 79039 : if (add_change) {
111 : // Find correct rtarget route flags if not already known.
112 42291 : if (!flags)
113 38050 : flags = GetRTargetRouteFlag(rtarget);
114 42291 : req.data.reset(new RTargetTable::RequestData(attr, flags, 0, 0, 0));
115 42291 : req.oper = DBRequest::DB_ENTRY_ADD_CHANGE;
116 : } else {
117 36748 : req.oper = DBRequest::DB_ENTRY_DELETE;
118 : }
119 79039 : Enqueue(&req);
120 79039 : }
121 :
122 1077 : void BgpXmppRTargetManager::ASNUpdateCallback(as_t old_asn,
123 : as_t old_local_asn) const {
124 1077 : if (local_autonomous_system() == (int)old_local_asn)
125 485 : return;
126 1077 : if (IsSubscriptionEmpty())
127 485 : return;
128 :
129 : // Delete the route and add with new local ASN
130 592 : BgpAttrPtr attr = GetRouteTargetRouteAttr();
131 592 : for (PublishedRTargetRoutes::const_iterator it = rtarget_routes_.begin();
132 6357 : it != rtarget_routes_.end(); it++) {
133 5765 : RTargetRouteOp(old_local_asn, it->first, NULL, false);
134 5765 : RTargetRouteOp(local_autonomous_system(), it->first, attr, true);
135 : }
136 592 : }
137 :
138 57905 : void BgpXmppRTargetManager::AddNewRTargetRoute(RoutingInstance *rtinstance,
139 : const RouteTarget &rtarget, BgpAttrPtr attr) {
140 57905 : PublishedRTargetRoutes::iterator rt_loc = rtarget_routes_.find(rtarget);
141 57905 : if (rt_loc == rtarget_routes_.end()) {
142 : pair<PublishedRTargetRoutes::iterator, bool> ret =
143 31019 : rtarget_routes_.insert(make_pair(rtarget, RoutingInstanceList()));
144 :
145 31019 : rt_loc = ret.first;
146 :
147 : // Send rtarget route ADD
148 31019 : RTargetRouteOp(local_autonomous_system(), rtarget, attr, true);
149 : }
150 57905 : rt_loc->second.insert(rtinstance);
151 57905 : }
152 :
153 4441 : void BgpXmppRTargetManager::DeleteRTargetRoute(
154 : RoutingInstance *rtinstance, const RouteTarget &rtarget) {
155 4441 : PublishedRTargetRoutes::iterator rt_loc = rtarget_routes_.find(rtarget);
156 4442 : assert(rt_loc != rtarget_routes_.end());
157 4442 : assert(rt_loc->second.erase(rtinstance));
158 4441 : if (rt_loc->second.empty()) {
159 3181 : rtarget_routes_.erase(rtarget);
160 : // Send rtarget route DELETE
161 3181 : RTargetRouteOp(local_autonomous_system(), rtarget, NULL, false);
162 : }
163 4442 : }
164 :
165 1325 : void BgpXmppRTargetManager::RoutingInstanceCallback(
166 : RoutingInstance *rt_instance, RouteTargetList *targets) {
167 : // Import list in the routing instance
168 1325 : const RouteTargetList &new_list = rt_instance->GetImportList();
169 :
170 : // Previous route target list for which the rtarget route was added
171 1325 : RouteTargetList *current = targets;
172 1325 : RouteTargetList::iterator cur_next_it, cur_it;
173 1325 : cur_it = cur_next_it = current->begin();
174 1325 : RouteTargetList::const_iterator new_it = new_list.begin();
175 :
176 1325 : pair<RouteTargetList::iterator, bool> r;
177 1325 : BgpAttrPtr attr = GetRouteTargetRouteAttr();
178 137774 : while (cur_it != current->end() && new_it != new_list.end()) {
179 136449 : if (*new_it < *cur_it) {
180 219 : r = current->insert(*new_it);
181 219 : assert(r.second);
182 219 : AddNewRTargetRoute(rt_instance, *new_it, attr);
183 219 : new_it++;
184 136230 : } else if (*new_it > *cur_it) {
185 966 : cur_next_it++;
186 966 : DeleteRTargetRoute(rt_instance, *cur_it);
187 966 : current->erase(cur_it);
188 966 : cur_it = cur_next_it;
189 : } else {
190 : // Update
191 135264 : cur_it++;
192 135264 : new_it++;
193 : }
194 136449 : cur_next_it = cur_it;
195 : }
196 1515 : for (; new_it != new_list.end(); ++new_it) {
197 190 : r = current->insert(*new_it);
198 190 : assert(r.second);
199 190 : AddNewRTargetRoute(rt_instance, *new_it, attr);
200 : }
201 1325 : for (cur_next_it = cur_it;
202 1325 : cur_it != current->end();
203 0 : cur_it = cur_next_it) {
204 0 : cur_next_it++;
205 0 : DeleteRTargetRoute(rt_instance, *cur_it);
206 0 : current->erase(cur_it);
207 : }
208 1325 : }
209 :
210 861 : void BgpXmppRTargetManager::UpdateRouteTargetRouteFlag(
211 : RoutingInstance *routing_instance, const RouteTargetList &targets,
212 : uint32_t flags) const {
213 861 : BgpAttrPtr attr = GetRouteTargetRouteAttr();
214 9343 : BOOST_FOREACH(RouteTarget rtarget, targets) {
215 : // Update route target route [llgr-]stale flag status.
216 4241 : RTargetRouteOp(local_autonomous_system(), rtarget, attr, true, flags);
217 : }
218 861 : }
219 :
220 6178 : void BgpXmppRTargetManager::Close() {
221 6178 : if (rtarget_routes_.empty())
222 2869 : return;
223 :
224 3309 : for (PublishedRTargetRoutes::iterator it = rtarget_routes_.begin();
225 31111 : it != rtarget_routes_.end(); it++) {
226 27802 : RTargetRouteOp(local_autonomous_system(), it->first, NULL, false);
227 : }
228 3309 : rtarget_routes_.clear();
229 : }
230 :
231 251 : void BgpXmppRTargetManager::Stale(const RouteTargetList &targets) const {
232 251 : BgpAttrPtr attr = GetRouteTargetRouteAttr();
233 :
234 : // Update route targets to clear STALE flag.
235 2783 : BOOST_FOREACH(RouteTarget rtarget, targets) {
236 : PublishedRTargetRoutes::const_iterator rt_loc =
237 1266 : rtarget_routes_.find(rtarget);
238 1266 : assert(rt_loc != rtarget_routes_.end());
239 :
240 : // Send rtarget route ADD
241 1266 : RTargetRouteOp(local_autonomous_system(), rtarget, attr, true);
242 : }
243 251 : }
244 :
245 : // Add/Delete rtarget route for import route target of the routing instance.
246 15023 : void BgpXmppRTargetManager::PublishRTargetRoute(RoutingInstance *rt_instance,
247 : bool add_change) {
248 15023 : if (IsSubscriptionEmpty())
249 72 : return;
250 :
251 14952 : if (add_change) {
252 129044 : BOOST_FOREACH(RouteTarget rtarget, GetSubscribedRTargets(rt_instance)) {
253 57494 : AddNewRTargetRoute(rt_instance, rtarget, GetRouteTargetRouteAttr());
254 : }
255 : } else {
256 7852 : BOOST_FOREACH(RouteTarget rtarget, GetSubscribedRTargets(rt_instance)) {
257 3475 : DeleteRTargetRoute(rt_instance, rtarget);
258 : }
259 : }
260 : }
261 :
262 1900 : void BgpXmppRTargetManager::FillInfo(BgpNeighborRoutingInstance *instance,
263 : const RouteTargetList &targets) const {
264 1900 : vector<string> import_targets;
265 13300 : BOOST_FOREACH(RouteTarget rt, targets) {
266 5700 : import_targets.push_back(rt.ToString());
267 : }
268 1900 : instance->set_import_targets(import_targets);
269 1900 : }
|