Line data Source code
1 : /*
2 : * Copyright (c) 2023 Matvey Kraposhin
3 : */
4 : extern "C" {
5 : #include <errno.h>
6 : #include <net/if.h>
7 : #include <sys/socket.h>
8 : #include <unistd.h>
9 : #include <linux/netlink.h>
10 : #include <linux/rtnetlink.h>
11 : #include <linux/neighbour.h>
12 : #include <linux/if_addr.h>
13 : #include <arpa/inet.h>
14 : }
15 : #include <cstring>
16 : #include <cmn/agent_cmn.h>
17 : #include <oper/interface_common.h>
18 : #include <oper/route_common.h>
19 : #include <oper/inet_unicast_route.h>
20 : #include <oper/global_vrouter.h>
21 : #include <oper/vxlan_routing_manager.h>
22 : #include "services/metadata_proxy.h"
23 : #include "services/metadata_server.h"
24 : #include "services/services_init.h"
25 :
26 25 : int MetadataProxy::VhostIndex(const std::string& vhost_name) {
27 25 : if (vhost_name != std::string("")) {
28 25 : int intf_idx = if_nametoindex(vhost_name.c_str());
29 25 : if (intf_idx > 0)
30 0 : return intf_idx;
31 : }
32 25 : return 0;
33 : }
34 :
35 0 : void MetadataProxy::AdvertiseMetaDataLinkLocalRoutes(const VmInterface* vm_intf,
36 : const Ip6Address& ll_ip, const VrfEntry* intf_vrf) {
37 0 : if (vm_intf == NULL || intf_vrf == NULL) {
38 0 : return;
39 : }
40 :
41 0 : std::scoped_lock lock(ll_ipv6_addr_mutex_);
42 : {
43 : InetUnicastAgentRouteTable *intf_inet_table =
44 0 : intf_vrf->GetInet6UnicastRouteTable();
45 0 : if (intf_inet_table == NULL)
46 0 : return;
47 : InetUnicastRouteEntry* rt_entry =
48 0 : intf_inet_table->FindRoute(ll_ip);
49 : // explicitly forbid advertisement of LL IPv6 route
50 : // if another with the given prefix exists
51 0 : if (rt_entry != NULL &&
52 0 : rt_entry->prefix_address().to_v6() == ll_ip &&
53 0 : rt_entry->prefix_length() == 128) {
54 0 : return;
55 : }
56 0 : VnListType vn_list;
57 0 : if (vm_intf->vn())
58 0 : vn_list.insert(vm_intf->vn()->GetName());
59 :
60 0 : InetInterfaceKey intf_key(vm_intf->name());
61 : InetInterfaceRoute *data = new InetInterfaceRoute
62 0 : (intf_key, vm_intf->label(), TunnelType::MplsType(),
63 0 : vn_list, vm_intf->peer()->sequence_number());
64 :
65 0 : DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE);
66 0 : req.key.reset(new InetUnicastRouteKey(vm_intf->peer(),
67 0 : intf_vrf->GetName(), ll_ip, 128));
68 0 : req.data.reset(data);
69 :
70 0 : intf_inet_table->Process(req);
71 0 : }
72 :
73 0 : ll_ipv6_addresses_.insert(std::make_pair(vm_intf->name(), ll_ip));
74 0 : }
75 :
76 14 : void MetadataProxy::DeleteMetaDataLinkLocalRoute(const VmInterface* vm_intf) {
77 14 : if (vm_intf == NULL)
78 14 : return;
79 :
80 14 : std::scoped_lock lock(ll_ipv6_addr_mutex_);
81 :
82 14 : Ip6Address ll_ip = Ip6Address::from_string(std::string("::"));
83 14 : if (!ll_ipv6_addresses_.count(vm_intf->name()))
84 14 : return;
85 :
86 0 : ll_ip = ll_ipv6_addresses_.at(vm_intf->name());
87 0 : const VrfEntry *vrf_entry = services_->agent()->
88 0 : vrf_table()->FindVrfFromName(vm_intf->vrf_name());
89 0 : if (!vrf_entry)
90 0 : return;
91 :
92 0 : DBEntryBase::KeyPtr tintf_key_ptr;
93 0 : InetUnicastRouteEntry *c_entry = NULL;
94 :
95 0 : tintf_key_ptr = vm_intf->GetDBRequestKey();
96 : const VmInterfaceKey* intf_key_ptr =
97 0 : dynamic_cast<const VmInterfaceKey *>(tintf_key_ptr.get());
98 0 : if (!intf_key_ptr)
99 0 : return;
100 :
101 0 : c_entry = vrf_entry->GetUcRoute(ll_ip);
102 0 : if (!c_entry)
103 0 : return;
104 :
105 : {
106 : InetUnicastAgentRouteTable *fabric_inet =
107 0 : services_->agent()->fabric_vrf()->
108 0 : GetInet6UnicastRouteTable();
109 0 : fabric_inet->Delete(services_->agent()->evpn_routing_peer(),
110 0 : services_->agent()->fabric_vrf_name(), ll_ip, 128);
111 : }
112 : {
113 0 : VnListType vn_list;
114 0 : if (vm_intf->vn())
115 0 : vn_list.insert(vm_intf->vn()->GetName());
116 0 : InetInterfaceKey intf_key(vm_intf->name());
117 : // InetInterfaceRoute *data = new InetInterfaceRoute
118 : // (intf_key, vm_intf->label(), local_path->GetTunnelType(),
119 : // local_path->dest_vn_list(), local_path->sequence());
120 : InetInterfaceRoute *data = new InetInterfaceRoute
121 0 : (intf_key, vm_intf->label(), TunnelType::MplsType(),
122 0 : vn_list, vm_intf->peer()->sequence_number());
123 :
124 : InetUnicastAgentRouteTable *table =
125 0 : vrf_entry->GetInet6UnicastRouteTable();
126 0 : if (table) {
127 0 : table->Delete(
128 : vm_intf->peer(),
129 : vrf_entry->GetName(),
130 0 : ll_ip, c_entry->prefix_length(),
131 : data);
132 : }
133 0 : }
134 :
135 0 : if (ll_ipv6_addresses_.count(vm_intf->name())) {
136 0 : ll_ipv6_addresses_.erase(vm_intf->name());
137 : }
138 14 : }
139 :
140 1 : const Ip6Address& MetadataProxy::Ipv6ServiceAddress() const {
141 1 : return ipv6_service_address_;
142 : }
143 :
144 1 : void MetadataProxy::InitializeHttp6Server(const VmInterface *vhost0) {
145 2 : if (vhost0 == NULL ||
146 1 : !ipv6_service_address_.is_unspecified()) {
147 0 : return;
148 : }
149 1 : if (!NetlinkGetVhostIp(ipv6_service_address_)) {
150 1 : LOG(ERROR, "An error has occured during retrieving IPv6 ll"
151 : " address from vhost0 in"
152 : " MetadataProxy::InitializeHttp6Server");
153 1 : return;
154 : }
155 0 : const int vhost_idx = VhostIndex(
156 0 : this->services_->agent()->vhost_interface_name());
157 0 : http_server6_->RegisterHandler(HTTP_WILDCARD_ENTRY,
158 : boost::bind(&MetadataProxy::HandleMetadataRequest, this, _1, _2));
159 0 : http_server6_->Initialize(
160 0 : services_->agent()->metadata_server_port(),
161 0 : ipv6_service_address_, vhost_idx);
162 0 : AdvertiseVhostRoute();
163 : }
164 :
165 0 : void MetadataProxy::AdvertiseVhostRoute() {
166 0 : PathPreference path_preference;
167 0 : EcmpLoadBalance ecmp_load_balance;
168 :
169 0 : Agent *agent = services_->agent();
170 :
171 : const VmInterface *vhost_intf =
172 0 : dynamic_cast<const VmInterface*>(agent->vhost_interface());
173 :
174 0 : VnListType vn_list;
175 0 : vn_list.insert(agent->fabric_vn_name());
176 :
177 : InetUnicastAgentRouteTable *table =
178 : static_cast<InetUnicastAgentRouteTable*>
179 0 : (agent->vrf_table()->GetInet6UnicastRouteTable(
180 : agent->fabric_vrf_name()));
181 :
182 0 : table->AddLocalVmRouteReq(
183 : agent->link_local_peer(), agent->fabric_vrf_name(),
184 0 : Ipv6ServiceAddress(), 128, vhost_intf->GetUuid(),
185 0 : vn_list, vhost_intf->label(), SecurityGroupList(),
186 0 : TagList(), CommunityList(), true, path_preference,
187 0 : Ip6Address(), ecmp_load_balance, false, false, false,
188 : vhost_intf->name());
189 0 : }
190 :
191 1 : void MetadataProxy::DeleteVhostRoute() {
192 1 : Agent *agent = services_->agent();
193 :
194 1 : InetUnicastAgentRouteTable::Delete(agent->link_local_peer(),
195 : agent->fabric_vrf_name(),
196 1 : Ipv6ServiceAddress(), 128);
197 1 : }
198 :
199 78 : void MetadataProxy::OnAVrfChange(DBTablePartBase *, DBEntryBase * entry) {
200 :
201 78 : VrfEntry *vrf_entry = dynamic_cast<VrfEntry*>(entry);
202 :
203 156 : if (vrf_entry == nullptr ||
204 78 : vrf_entry != services_->agent()->fabric_vrf()) {
205 69 : return;
206 : }
207 :
208 : InetUnicastAgentRouteTable *fabric_inet6_table =
209 9 : vrf_entry->GetInet6UnicastRouteTable();
210 9 : if (fabric_inet6_table == nullptr) {
211 3 : return;
212 : }
213 :
214 11 : if (vrf_entry->IsDeleted() &&
215 5 : fabric_notify_id_ >= 0) {
216 1 : fabric_inet6_table->Unregister(fabric_notify_id_);
217 1 : fabric_notify_id_ = -1;
218 : }
219 :
220 7 : if (!vrf_entry->IsDeleted() &&
221 1 : fabric_notify_id_ < 0) {
222 1 : fabric_notify_id_ =
223 1 : fabric_inet6_table->Register(
224 : boost::bind(&MetadataProxy::OnAFabricRouteChange,
225 : this, _1, _2));
226 : }
227 : }
228 :
229 28 : void MetadataProxy::OnAFabricRouteChange
230 : (DBTablePartBase *, DBEntryBase *entry) {
231 :
232 : InetUnicastAgentRouteTable *inet_table =
233 28 : dynamic_cast<InetUnicastAgentRouteTable*>(entry->get_table());
234 28 : if (!inet_table)
235 16 : return;
236 :
237 : InetUnicastRouteEntry *route_entry =
238 28 : dynamic_cast<InetUnicastRouteEntry*>(entry);
239 28 : if (!route_entry)
240 0 : return;
241 :
242 28 : const AgentPath *active_path = route_entry->GetActivePath();
243 28 : const NextHop *active_nh = active_path ? active_path->nexthop() : NULL;
244 : const InterfaceNH *interface_nh =
245 28 : dynamic_cast<const InterfaceNH*>(active_nh);
246 28 : if (interface_nh == NULL) {
247 16 : return;
248 : }
249 :
250 12 : const VmInterface *interface = dynamic_cast<const VmInterface*>(
251 12 : interface_nh->GetInterface());
252 12 : if (interface == NULL) {
253 0 : return;
254 : }
255 :
256 12 : const Ip6Address mip6 = interface->mdata_ip6_addr();
257 :
258 12 : if (mip6 == route_entry->prefix_address().to_v6()) {
259 12 : if (entry->IsDeleted()) {
260 : } else {
261 : // Create a neighbour record (ip neigh add ...)
262 12 : this->NetlinkAddVhostNb(mip6, interface->vm_mac());
263 :
264 : // Create a routing record (ip route add)
265 12 : this->NetlinkAddInterfaceRoute(mip6);
266 : }
267 : }
268 : }
269 :
270 82 : void MetadataProxy::OnAnInterfaceChange(DBTablePartBase *, DBEntryBase *entry) {
271 82 : VmInterface *vmi = dynamic_cast<VmInterface *>(entry);
272 82 : if (!vmi)
273 15 : return;
274 :
275 67 : if (vmi->IsDeleted() && vmi != services_->agent()->vhost_interface()) {
276 14 : DeleteMetaDataLinkLocalRoute(vmi);
277 14 : return;
278 : }
279 :
280 53 : if (!vmi->IsDeleted() && vmi == services_->agent()->vhost_interface()) {
281 1 : InitializeHttp6Server(vmi);
282 : }
283 :
284 53 : if (vmi->IsDeleted() && vmi == services_->agent()->vhost_interface()) {
285 1 : this->DeleteVhostRoute();
286 : }
287 : }
288 :
289 1 : void MetadataProxy::RegisterListeners() {
290 1 : vrf_table_notify_id_ = -1;
291 1 : intf_table_notify_id_ = -1;
292 1 : fabric_notify_id_ = -1; // Will be registered later,
293 : // since the table isn't present now
294 1 : if (services_->agent()->vrf_table()) {
295 1 : vrf_table_notify_id_ =
296 1 : services_->agent()->vrf_table()->Register(
297 : boost::bind(&MetadataProxy::OnAVrfChange, this, _1, _2));
298 : }
299 1 : if (services_->agent()->interface_table()) {
300 1 : intf_table_notify_id_ =
301 1 : services_->agent()->interface_table()->Register(
302 : boost::bind(&MetadataProxy::OnAnInterfaceChange, this, _1, _2));
303 : }
304 1 : }
305 :
306 1 : void MetadataProxy::UnregisterListeners() {
307 1 : if (vrf_table_notify_id_ > -1) {
308 1 : services_->agent()->vrf_table()->
309 1 : Unregister(vrf_table_notify_id_);
310 1 : vrf_table_notify_id_ = -1;
311 : }
312 1 : if (intf_table_notify_id_ > -1) {
313 1 : services_->agent()->interface_table()->
314 1 : Unregister(intf_table_notify_id_);
315 1 : intf_table_notify_id_ = -1;
316 : }
317 1 : }
318 :
319 : //
320 : // END-OF-FILE
321 : //
|