Line data Source code
1 : /*
2 : * Copyright (c) 2018 Juniper Networks, Inc. All rights reserved.
3 : * Copyright (c) 2022 - 2026 Matvey Kraposhin.
4 : * Copyright (c) 2024 - 2026 Elena Zizganova.
5 : */
6 :
7 : #include <oper/operdb_init.h>
8 : #include <oper/route_common.h>
9 : #include <oper/vrf.h>
10 : #include <oper/bridge_route.h>
11 : #include <oper/inet_unicast_route.h>
12 : #include <oper/evpn_route.h>
13 : #include <oper/agent_route.h>
14 : #include <oper/vn.h>
15 : #include <oper/vrf.h>
16 : #include <controller/controller_route_path.h>
17 : #include <oper/vxlan_routing_manager.h>
18 : #include <oper/tunnel_nh.h>
19 : #include <oper/bgp_as_service.h>
20 :
21 : template<class RouteTable, class RouteEntry>
22 : static const AgentPath *LocalVmExportInterface(Agent* agent,
23 : RouteTable *table, RouteEntry *route);
24 :
25 0 : TunnelNHKey* VxlanRoutingManager::AllocateTunnelNextHopKey(
26 : const IpAddress& dip, const MacAddress& dmac) const {
27 :
28 0 : const Ip4Address rtr_dip = dip.to_v4();
29 :
30 0 : const std::vector<IpAddress> nh_addresses(1, dip);
31 0 : bool is_zero_mac = dmac.IsZero();
32 :
33 0 : MacAddress rtr_dmac;
34 0 : if (!is_zero_mac) {
35 0 : rtr_dmac = dmac;
36 : } else {
37 0 : rtr_dmac = NbComputeMac(rtr_dip, agent_);
38 : }
39 :
40 0 : TunnelNHKey *tun_nh_key = new TunnelNHKey(agent_->fabric_vrf_name(),
41 0 : agent_->router_id(),
42 : rtr_dip,
43 : false,
44 0 : TunnelType(TunnelType::VXLAN),
45 0 : rtr_dmac);
46 0 : return tun_nh_key;
47 0 : }
48 :
49 0 : void VxlanRoutingManager::XmppAdvertiseEvpnRoute(const IpAddress& prefix_ip,
50 : const int prefix_len, uint32_t vxlan_id, const std::string vrf_name,
51 : const RouteParameters& params, const Peer *bgp_peer,
52 : const std::vector<std::string> &peer_sources) {
53 0 : VrfEntry* vrf = agent_->vrf_table()->FindVrfFromName(vrf_name);
54 : EvpnAgentRouteTable *evpn_table =
55 0 : dynamic_cast<EvpnAgentRouteTable*>(vrf->GetEvpnRouteTable());
56 0 : if (evpn_table == NULL) {
57 0 : return;
58 : }
59 :
60 : // If route is a tunnel
61 0 : if (agent_->router_id() != params.nh_addr_.to_v4()) {
62 0 : XmppAdvertiseEvpnTunnel(evpn_table,
63 : prefix_ip, prefix_len, vxlan_id, vrf_name, params, bgp_peer);
64 0 : return;
65 : }
66 :
67 : // Or this is an interface
68 0 : XmppAdvertiseEvpnInterface(evpn_table,
69 : prefix_ip, prefix_len, vxlan_id, vrf_name, params, bgp_peer, peer_sources);
70 : }
71 :
72 0 : void VxlanRoutingManager::XmppAdvertiseInetRoute(const IpAddress& prefix_ip,
73 : const int prefix_len, const std::string vrf_name,
74 : const AgentPath* path) {
75 :
76 0 : VrfEntry* vrf = agent_->vrf_table()->FindVrfFromName(vrf_name);
77 : InetUnicastAgentRouteTable *inet_table =
78 0 : vrf->GetInetUnicastRouteTable(prefix_ip);
79 :
80 0 : if (path->nexthop() && path->nexthop()->GetType() ==
81 : NextHop::TUNNEL) {
82 0 : XmppAdvertiseInetTunnel(inet_table,
83 : prefix_ip, prefix_len, vrf_name, path);
84 0 : return;
85 : }
86 :
87 0 : if (path->nexthop() &&
88 0 : (path->nexthop()->GetType() == NextHop::INTERFACE ||
89 0 : path->nexthop()->GetType() == NextHop::COMPOSITE)) {
90 0 : XmppAdvertiseInetInterfaceOrComposite(inet_table,
91 : prefix_ip, prefix_len, vrf_name, path);
92 : }
93 : }
94 :
95 0 : void VxlanRoutingManager::XmppAdvertiseEvpnTunnel(
96 : EvpnAgentRouteTable *evpn_table, const IpAddress& prefix_ip,
97 : const int prefix_len, uint32_t vxlan_id, const std::string vrf_name,
98 : const RouteParameters& params, const Peer *peer
99 : ) {
100 0 : const BgpPeer *bgp_peer = dynamic_cast<const BgpPeer*>(peer);
101 0 : if (bgp_peer == NULL) {
102 0 : return;
103 : }
104 0 : DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE);
105 : std::unique_ptr<TunnelNHKey> tun_nh_key (AllocateTunnelNextHopKey(
106 0 : params.nh_addr_, params.nh_mac_));
107 :
108 : ControllerVmRoute *data =
109 0 : ControllerVmRoute::MakeControllerVmRoute(dynamic_cast<const BgpPeer*>(bgp_peer),
110 0 : agent_->fabric_vrf_name(),
111 0 : agent_->router_id(),
112 : vrf_name,
113 : tun_nh_key->dip(),
114 : TunnelType::VxlanType(),
115 : vxlan_id,
116 : tun_nh_key->rewrite_dmac(),
117 : params.vn_list_,
118 : params.sg_list_,
119 : params.tag_list_,
120 : params.path_preference_,
121 : true,
122 0 : EcmpLoadBalance(),
123 : false);
124 0 : evpn_table->AddRemoteVmRouteReq(bgp_peer,
125 : vrf_name,
126 0 : MacAddress(),
127 : prefix_ip,
128 : prefix_len,
129 : 0, // ethernet_tag is zero for Type5
130 : data);
131 0 : }
132 :
133 0 : void VxlanRoutingManager::XmppAdvertiseEvpnBgpaasInterface(
134 : EvpnAgentRouteTable *evpn_table, const IpAddress& prefix_ip,
135 : const int prefix_len, uint32_t vxlan_id, const std::string vrf_name,
136 : const RouteParameters& params, const Peer *bgp_peer, const NextHop *nh
137 : ) {
138 0 : const InterfaceNH *intf_nh = dynamic_cast<const InterfaceNH *>(nh);
139 0 : const Interface *intf = intf_nh->GetInterface();
140 0 : if (intf->type() != Interface::VM_INTERFACE) {
141 0 : return;
142 : }
143 0 : const VmInterface *vm_intf = dynamic_cast<const VmInterface*>
144 0 : (intf);
145 0 : DBEntryBase::KeyPtr tintf_key_ptr = vm_intf->GetDBRequestKey();
146 : const VmInterfaceKey* intf_key_ptr =
147 0 : dynamic_cast<const VmInterfaceKey *>(tintf_key_ptr.get());
148 :
149 : LocalVmRoute *loc_rt_ptr = new LocalVmRoute(
150 : *intf_key_ptr,
151 : MplsTable::kInvalidLabel, // mpls_label
152 : vxlan_id,
153 : false,
154 : params.vn_list_,
155 0 : intf_nh->GetFlags(), // flags
156 : params.sg_list_,
157 : params.tag_list_,
158 : params.communities_,
159 : params.path_preference_,
160 0 : Ip4Address(0),
161 : params.ecmp_load_balance_,
162 : false,
163 : false,
164 0 : params.sequence_number_,
165 : false,
166 0 : false); // native_encap
167 0 : loc_rt_ptr->set_tunnel_bmap(TunnelType::VxlanType());
168 :
169 : {
170 0 : DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE);
171 :
172 0 : req.key.reset(new EvpnRouteKey(bgp_peer,
173 0 : evpn_table->vrf_entry()->GetName(),
174 0 : MacAddress(),
175 : prefix_ip,
176 : prefix_len,
177 0 : 0));
178 0 : req.data.reset(loc_rt_ptr);
179 0 : evpn_table->Enqueue(&req);
180 0 : }
181 0 : }
182 :
183 0 : void VxlanRoutingManager::XmppAdvertiseEvpnBgpaasComposite(
184 : EvpnAgentRouteTable *evpn_table, const IpAddress& prefix_ip,
185 : const int prefix_len, uint32_t vxlan_id, const std::string vrf_name,
186 : const RouteParameters& params, const Peer *bgp_peer,
187 : ComponentNHKeyList &comp_nh_list ) {
188 0 : DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE);
189 0 : const bool comp_nh_policy = true;
190 : CompositeNHKey *new_comp_nh_key =
191 : new CompositeNHKey(Composite::LOCAL_ECMP,
192 0 : comp_nh_policy, comp_nh_list, vrf_name);
193 :
194 0 : nh_req.key.reset(new_comp_nh_key);
195 0 : nh_req.data.reset(new CompositeNHData());
196 0 : const BgpPeer *bgp_peer_ecmp = dynamic_cast<const BgpPeer*>(bgp_peer);
197 0 : std::stringstream prefix_str;
198 0 : prefix_str << prefix_ip.to_string();
199 0 : prefix_str << "/";
200 0 : prefix_str << prefix_len;
201 :
202 : ControllerEcmpRoute *rt_data = new ControllerEcmpRoute(
203 : bgp_peer_ecmp,
204 : params.vn_list_,
205 : params.ecmp_load_balance_,
206 : params.tag_list_,
207 : params.sg_list_,
208 : params.path_preference_,
209 0 : TunnelType::VxlanType(),
210 : nh_req,
211 0 : prefix_str.str(),
212 0 : evpn_table->vrf_name());
213 :
214 : ControllerEcmpRoute::ClonedLocalPathListIter iter =
215 0 : rt_data->cloned_local_path_list().begin();
216 0 : while (iter != rt_data->cloned_local_path_list().end()) {
217 0 : evpn_table->AddClonedLocalPathReq(bgp_peer_ecmp, vrf_name,
218 0 : MacAddress(), prefix_ip, 0, (*iter));
219 0 : iter++;
220 : }
221 :
222 0 : evpn_table->AddRemoteVmRouteReq(bgp_peer_ecmp,
223 0 : vrf_name, MacAddress(),
224 : prefix_ip,
225 : prefix_len,
226 : 0, // ethernet tag is 0 for VxLAN
227 : rt_data);
228 0 : }
229 :
230 0 : void VxlanRoutingManager::XmppAdvertiseEvpnBgpaas(
231 : EvpnAgentRouteTable *evpn_table, const IpAddress& prefix_ip,
232 : const int prefix_len, uint32_t vxlan_id, const std::string vrf_name,
233 : const RouteParameters& params, const Peer *bgp_peer,
234 : const std::vector<std::string> &peer_sources
235 : ) {
236 0 : const NextHop *first_intf_nh = nullptr;
237 0 : NextHopKey *nh_key = nullptr;
238 : // Create a new composite
239 0 : ComponentNHKeyList new_comp_nh_list;
240 0 : for (auto &nexthop_addr : peer_sources) {
241 0 : IpAddress nh_ip;
242 0 : boost::system::error_code ec;
243 : int nh_ip_len;
244 0 : if (is_ipv4_string(nexthop_addr)) {
245 0 : nh_ip = Ip4Address::from_string(ipv4_prefix(nexthop_addr), ec);
246 0 : nh_ip_len = ipv4_prefix_len(nexthop_addr);
247 0 : } else if (is_ipv6_string(nexthop_addr)) {
248 0 : nh_ip = Ip6Address::from_string(ipv6_prefix(nexthop_addr), ec);
249 0 : nh_ip_len = ipv6_prefix_len(nexthop_addr);
250 : } else {
251 0 : LOG(ERROR, "Error in VxlanRoutingManager::AddInterfaceComponentToList"
252 : << ", nexthop_addr = " << nexthop_addr
253 : << " is not an IPv4 or IPv6 prefix");
254 0 : return;
255 : }
256 0 : if (ec) {
257 0 : continue;
258 : }
259 0 : EvpnRouteEntry *route =evpn_table->FindRoute(MacAddress(),
260 : nh_ip, nh_ip_len, 0);
261 : const AgentPath *loc_path =
262 0 : LocalVmExportInterface(agent_, evpn_table, route);
263 0 : if (loc_path == nullptr) {
264 0 : continue;
265 : }
266 0 : if (loc_path->nexthop() == nullptr) {
267 0 : continue;
268 : }
269 0 : if (IsBgpaasInterfaceNexthop(agent_, loc_path->nexthop())) {
270 0 : if (first_intf_nh == NULL) {
271 0 : first_intf_nh = loc_path->nexthop();
272 : }
273 0 : DBEntryBase::KeyPtr key = loc_path->nexthop()->
274 0 : GetDBRequestKey();
275 0 : nh_key = static_cast<NextHopKey *>(key.release());
276 :
277 0 : std::unique_ptr<const NextHopKey> nh_key_ptr(nh_key);
278 : ComponentNHKeyPtr component_nh_key(new ComponentNHKey(
279 0 : MplsTable::kInvalidLabel, std::move(nh_key_ptr)));
280 0 : new_comp_nh_list.push_back(component_nh_key);
281 0 : } else if (IsBgpaasCompositeNexthop(agent_, loc_path->nexthop())) {
282 0 : const CompositeNH *composite_nh = dynamic_cast<const CompositeNH*>(
283 0 : loc_path->nexthop());
284 0 : const ComponentNHList &components = composite_nh->component_nh_list();
285 0 : for (auto &component : components) {
286 0 : if (component.get() &&
287 0 : component->nh() &&
288 0 : component->nh()->GetType() == NextHop::INTERFACE) {
289 0 : if (first_intf_nh == nullptr) {
290 0 : first_intf_nh = component->nh();
291 : }
292 0 : DBEntryBase::KeyPtr key = component->nh()->
293 0 : GetDBRequestKey();
294 0 : nh_key = static_cast<NextHopKey *>(key.release());
295 :
296 0 : std::unique_ptr<const NextHopKey> nh_key_ptr(nh_key);
297 : ComponentNHKeyPtr component_nh_key(new ComponentNHKey(
298 0 : MplsTable::kInvalidLabel, std::move(nh_key_ptr)));
299 0 : new_comp_nh_list.push_back(component_nh_key);
300 0 : }
301 : }
302 : }
303 : }
304 :
305 0 : if (new_comp_nh_list.size() < 1) {
306 0 : return;
307 0 : } else if (new_comp_nh_list.size() == 1) {
308 0 : XmppAdvertiseEvpnBgpaasInterface(evpn_table, prefix_ip, prefix_len,
309 : vxlan_id, vrf_name, params, bgp_peer, first_intf_nh);
310 : } else {
311 0 : XmppAdvertiseEvpnBgpaasComposite(evpn_table, prefix_ip, prefix_len,
312 : vxlan_id, vrf_name, params, bgp_peer, new_comp_nh_list);
313 : }
314 :
315 0 : }
316 :
317 0 : void VxlanRoutingManager::XmppAdvertiseEvpnInterface(
318 : EvpnAgentRouteTable *evpn_table, const IpAddress& prefix_ip,
319 : const int prefix_len, uint32_t vxlan_id, const std::string vrf_name,
320 : const RouteParameters& params, const Peer *bgp_peer,
321 : const std::vector<std::string> &peer_sources ) {
322 0 : EvpnRouteEntry *route = evpn_table->FindRoute(MacAddress(),
323 : prefix_ip, prefix_len, 0);
324 0 : if (RoutePrefixIsEqualTo(route, prefix_ip, prefix_len) == false) {
325 0 : XmppAdvertiseEvpnBgpaas(evpn_table, prefix_ip, prefix_len, vxlan_id,
326 : vrf_name, params, bgp_peer, peer_sources);
327 0 : return;
328 : }
329 : const AgentPath * path =
330 0 : LocalVmExportInterface(agent_, evpn_table, route);
331 :
332 0 : if (!path ) {
333 0 : XmppAdvertiseEvpnBgpaas(evpn_table, prefix_ip, prefix_len, vxlan_id,
334 : vrf_name, params, bgp_peer, peer_sources);
335 0 : return;
336 : }
337 :
338 0 : CopyInterfacePathToEvpnTable(path,
339 : prefix_ip,
340 : prefix_len,
341 : bgp_peer,
342 0 : RouteParameters(IpAddress(), // NH address, not needed here
343 0 : MacAddress(),
344 : params.vn_list_,
345 : params.sg_list_,
346 : params.communities_,
347 : params.tag_list_,
348 : params.path_preference_,
349 : params.ecmp_load_balance_,
350 0 : params.sequence_number_),
351 : evpn_table);
352 : }
353 :
354 0 : void VxlanRoutingManager::XmppAdvertiseInetTunnel(
355 : InetUnicastAgentRouteTable *inet_table, const IpAddress& prefix_ip,
356 : const int prefix_len, const std::string vrf_name,
357 : const AgentPath* path) {
358 :
359 0 : DBRequest nh_req(DBRequest::DB_ENTRY_ADD_CHANGE);
360 0 : TunnelNH *tun_nh = dynamic_cast<TunnelNH*>(path->nexthop());
361 :
362 0 : TunnelNHKey *tun_nh_key = AllocateTunnelNextHopKey(*(tun_nh->GetDip()),
363 : tun_nh->rewrite_dmac());
364 0 : std::string origin_vn = "";
365 :
366 0 : nh_req.key.reset(tun_nh_key);
367 0 : nh_req.data.reset(new TunnelNHData);
368 :
369 0 : inet_table->AddEvpnRoutingRoute(prefix_ip,
370 : prefix_len,
371 0 : inet_table->vrf_entry(),
372 : routing_vrf_vxlan_bgp_peer_,
373 : path->sg_list(),
374 : path->communities(),
375 : path->path_preference(),
376 : path->ecmp_load_balance(),
377 : path->tag_list(),
378 : nh_req,
379 : path->vxlan_id(),
380 : path->dest_vn_list(),
381 : origin_vn);
382 0 : }
383 :
384 0 : void VxlanRoutingManager::XmppAdvertiseInetInterfaceOrComposite(
385 : InetUnicastAgentRouteTable *inet_table, const IpAddress& prefix_ip,
386 : const int prefix_len, const std::string vrf_name,
387 : const AgentPath* path) {
388 :
389 0 : CopyPathToInetTable(path,
390 : prefix_ip,
391 : prefix_len,
392 : routing_vrf_vxlan_bgp_peer_,
393 0 : RouteParameters(IpAddress(),
394 0 : MacAddress(),
395 : path->dest_vn_list(),
396 : path->sg_list(),
397 : path->communities(),
398 : path->tag_list(),
399 : path->path_preference(),
400 : path->ecmp_load_balance(),
401 : path->peer_sequence_number()),
402 : inet_table);
403 0 : }
404 :
405 : template<class RouteTable, class RouteEntry>
406 0 : static const AgentPath *LocalVmExportInterface(Agent* agent,
407 : RouteTable *table, RouteEntry *route) {
408 0 : if (table == NULL || agent == NULL || route == NULL) {
409 0 : return NULL;
410 : }
411 :
412 0 : const AgentPath *tm_path = NULL;
413 0 : const AgentPath *rt_path = NULL;
414 :
415 0 : for (Route::PathList::const_iterator it =
416 0 : route->GetPathList().begin();
417 0 : it != route->GetPathList().end(); it++) {
418 : tm_path =
419 0 : static_cast<const AgentPath *>(it.operator->());
420 0 : if (tm_path == NULL || tm_path->peer() == NULL) {
421 0 : continue;
422 : }
423 0 : if (tm_path->peer()->GetType() ==
424 0 : agent->local_vm_export_peer()->GetType()) {
425 0 : if (tm_path->nexthop() &&
426 0 : tm_path->nexthop()->GetType() == NextHop::INTERFACE) {
427 0 : rt_path = tm_path;
428 0 : } else if (tm_path->nexthop() &&
429 0 : tm_path->nexthop()->GetType() == NextHop::COMPOSITE) {
430 0 : return tm_path;
431 : }
432 : }
433 : }
434 0 : return rt_path;
435 : }
436 :
437 : //
438 : //END-OF-FILE
439 : //
440 :
|