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 : #include "base/os.h"
7 : #include "services/arp_proto.h"
8 : #include "services/services_sandesh.h"
9 : #include "services/services_init.h"
10 : #include "oper/route_common.h"
11 :
12 124 : ArpEntry::ArpEntry(boost::asio::io_context &io, ArpHandler *handler,
13 : ArpKey &key, const VrfEntry *vrf, State state,
14 124 : const Interface *itf)
15 372 : : io_(io), key_(key), nh_vrf_(vrf), state_(state), retry_count_(0),
16 124 : handler_(handler), arp_timer_(NULL), interface_(itf) {
17 124 : if (!IsDerived()) {
18 124 : arp_timer_ = TimerManager::CreateTimer(io, "Arp Entry timer",
19 : TaskScheduler::GetInstance()->GetTaskId("Agent::Services"),
20 : PktHandler::ARP);
21 : }
22 124 : }
23 :
24 248 : ArpEntry::~ArpEntry() {
25 124 : if (!IsDerived()) {
26 124 : arp_timer_->Cancel();
27 124 : TimerManager::DeleteTimer(arp_timer_);
28 : }
29 124 : handler_.reset(NULL);
30 248 : }
31 :
32 0 : void ArpEntry::HandleDerivedArpRequest() {
33 0 : ArpProto *arp_proto = handler_->agent()->GetArpProto();
34 : //Add ArpRoute for Derived entry
35 0 : AddArpRoute(IsResolved());
36 :
37 0 : ArpKey key(key_.ip, nh_vrf_);
38 0 : ArpEntry *entry = arp_proto->FindArpEntry(key);
39 0 : if (entry) {
40 0 : entry->HandleArpRequest();
41 : } else {
42 0 : entry = new ArpEntry(io_, handler_.get(), key, nh_vrf_, ArpEntry::INITING,
43 0 : interface_.get());
44 0 : if (arp_proto->AddArpEntry(entry) == false) {
45 0 : delete entry;
46 0 : return;
47 : }
48 0 : entry->HandleArpRequest();
49 : }
50 : }
51 :
52 4 : bool ArpEntry::HandleArpRequest() {
53 4 : if (IsDerived()) {
54 0 : HandleDerivedArpRequest();
55 0 : return true;
56 : }
57 4 : if (IsResolved())
58 0 : AddArpRoute(true);
59 : else {
60 4 : AddArpRoute(false);
61 4 : if (state_ & ArpEntry::INITING) {
62 2 : state_ = ArpEntry::RESOLVING;
63 2 : SendArpRequest();
64 : }
65 : }
66 4 : return true;
67 : }
68 :
69 0 : void ArpEntry::HandleArpReply(const MacAddress &mac) {
70 :
71 0 : if (IsDerived()) {
72 : /* We don't expect ARP replies in derived Vrf */
73 0 : return;
74 : }
75 0 : if ((state_ == ArpEntry::RESOLVING) || (state_ == ArpEntry::ACTIVE) ||
76 0 : (state_ == ArpEntry::INITING) || (state_ == ArpEntry::RERESOLVING)) {
77 0 : ArpProto *arp_proto = handler_->agent()->GetArpProto();
78 0 : arp_timer_->Cancel();
79 0 : retry_count_ = 0;
80 0 : mac_address_ = mac;
81 0 : if (state_ == ArpEntry::RESOLVING) {
82 0 : arp_proto->IncrementStatsResolved();
83 0 : arp_proto->IncrementStatsResolved(interface_->id());
84 : }
85 0 : state_ = ArpEntry::ACTIVE;
86 0 : StartTimer(arp_proto->aging_timeout(), ArpProto::AGING_TIMER_EXPIRED);
87 0 : AddArpRoute(true);
88 : }
89 : }
90 :
91 2 : bool ArpEntry::RetryExpiry() {
92 2 : if (state_ & ArpEntry::ACTIVE)
93 0 : return true;
94 2 : ArpProto *arp_proto = handler_->agent()->GetArpProto();
95 2 : if (retry_count_ < arp_proto->max_retries()) {
96 2 : retry_count_++;
97 2 : SendArpRequest();
98 : } else {
99 : std::vector<Ip4Address> gateway_list =
100 0 : handler_->agent()->vhost_default_gateway();
101 0 : Ip4Address ip(key_.ip);
102 0 : if (std::find(gateway_list.begin(), gateway_list.end(), ip) !=
103 0 : gateway_list.end()) {
104 0 : state_ = ArpEntry::RESOLVING;
105 0 : ARP_TRACE(Trace, "Retry exceeded, set arp to resolving",
106 : ip.to_string(), key_.vrf->GetName(), "");
107 : }
108 0 : ARP_TRACE(Trace, "Retry exceeded", ip.to_string(),
109 : key_.vrf->GetName(), "");
110 0 : arp_proto->IncrementStatsMaxRetries();
111 :
112 : // if Arp NH is not present, let the entry be deleted
113 0 : if (DeleteArpRoute())
114 0 : return false;
115 :
116 : // keep retrying till Arp NH is deleted
117 0 : retry_count_ = 0;
118 0 : SendArpRequest();
119 0 : }
120 2 : return true;
121 : }
122 :
123 0 : bool ArpEntry::AgingExpiry() {
124 0 : Ip4Address ip(key_.ip);
125 0 : const string& vrf_name = key_.vrf->GetName();
126 0 : ArpNHKey nh_key(vrf_name, ip, false);
127 0 : ArpNH *arp_nh = static_cast<ArpNH *>(handler_->agent()->nexthop_table()->
128 0 : FindActiveEntry(&nh_key));
129 0 : if (!arp_nh) {
130 : // do not re-resolve if Arp NH doesnt exist
131 0 : return false;
132 : }
133 0 : state_ = ArpEntry::RERESOLVING;
134 0 : SendArpRequest();
135 0 : return true;
136 0 : }
137 :
138 542 : void ArpEntry::SendGratuitousArp() {
139 542 : Agent *agent = handler_->agent();
140 542 : ArpProto *arp_proto = agent->GetArpProto();
141 542 : if (agent->router_id_configured()) {
142 542 : if (interface_->type() == Interface::VM_INTERFACE) {
143 : const VmInterface *vmi =
144 542 : static_cast<const VmInterface *>(interface_.get());
145 542 : MacAddress smac = vmi->GetVifMac(agent);
146 542 : if (key_.vrf && key_.vrf->vn()) {
147 500 : IpAddress gw_ip = key_.vrf->vn()->GetGatewayFromIpam
148 500 : (Ip4Address(key_.ip));
149 500 : IpAddress dns_ip = key_.vrf->vn()->GetDnsFromIpam
150 500 : (Ip4Address(key_.ip));
151 500 : if (!gw_ip.is_unspecified() && gw_ip.is_v4()) {
152 2000 : handler_->SendArp(ARPOP_REQUEST, smac,
153 500 : gw_ip.to_v4().to_ulong(),
154 1000 : smac, vmi->vm_mac(), gw_ip.to_v4().to_ulong(),
155 500 : vmi->id(), key_.vrf->vrf_id());
156 : }
157 1000 : if (!dns_ip.is_unspecified() && dns_ip.is_v4() &&
158 500 : dns_ip != gw_ip) {
159 0 : handler_->SendArp(ARPOP_REQUEST, smac,
160 0 : dns_ip.to_v4().to_ulong(),
161 0 : smac, vmi->vm_mac(), dns_ip.to_v4().to_ulong(),
162 0 : vmi->id(), key_.vrf->vrf_id());
163 : }
164 : }
165 : } else {
166 0 : handler_->SendArp(ARPOP_REQUEST, arp_proto->ip_fabric_interface_mac(),
167 0 : agent->router_id().to_ulong(), MacAddress(),
168 0 : MacAddress::BroadcastMac(), agent->router_id().to_ulong(),
169 : arp_proto->ip_fabric_interface_index(),
170 0 : key_.vrf->vrf_id());
171 : }
172 :
173 : }
174 :
175 542 : retry_count_++;
176 542 : StartTimer(ArpProto::kGratRetryTimeout, ArpProto::GRATUITOUS_TIMER_EXPIRED);
177 542 : }
178 :
179 4 : bool ArpEntry::IsResolved() {
180 4 : return (state_ & (ArpEntry::ACTIVE | ArpEntry::RERESOLVING));
181 : }
182 :
183 258 : bool ArpEntry::IsDerived() {
184 258 : if (key_.vrf != nh_vrf_) {
185 0 : return true;
186 : }
187 258 : return false;
188 : }
189 :
190 546 : void ArpEntry::StartTimer(uint32_t timeout, uint32_t mtype) {
191 546 : arp_timer_->Cancel();
192 1092 : arp_timer_->Start(timeout, boost::bind(&ArpProto::TimerExpiry,
193 546 : handler_->agent()->GetArpProto(),
194 546 : key_, mtype, interface_.get()));
195 546 : }
196 :
197 4 : void ArpEntry::SendArpRequest() {
198 4 : assert(!IsDerived());
199 4 : Agent *agent = handler_->agent();
200 4 : ArpProto *arp_proto = agent->GetArpProto();
201 4 : uint32_t vrf_id = VrfEntry::kInvalidIndex;
202 4 : uint32_t intf_id = arp_proto->ip_fabric_interface_index();
203 4 : Ip4Address ip;
204 4 : MacAddress smac;
205 4 : if (interface_->type() == Interface::VM_INTERFACE) {
206 : const VmInterface *vmi =
207 4 : static_cast<const VmInterface *>(interface_.get());
208 4 : ip = vmi->GetServiceIp(Ip4Address(key_.ip)).to_v4();
209 4 : if (vmi->vmi_type() == VmInterface::VHOST) {
210 4 : ip = agent->router_id();
211 : }
212 4 : vrf_id = nh_vrf_->vrf_id();
213 4 : if (vmi->parent()) {
214 4 : intf_id = vmi->parent()->id();
215 : }
216 4 : smac = vmi->GetVifMac(agent);
217 : } else {
218 0 : if (agent->is_l3mh() == true) {
219 0 : intf_id = interface_->id();
220 0 : ip = agent->ip_fabric_intf_addr_list()[intf_id];
221 : } else {
222 0 : ip = agent->router_id();
223 : }
224 : VrfEntry *vrf =
225 0 : agent->vrf_table()->FindVrfFromName(agent->fabric_vrf_name());
226 0 : if (vrf) {
227 0 : vrf_id = vrf->vrf_id();
228 : }
229 0 : smac = interface_->mac();
230 : }
231 :
232 4 : if (vrf_id != VrfEntry::kInvalidIndex) {
233 8 : handler_->SendArp(ARPOP_REQUEST, smac, ip.to_ulong(),
234 8 : MacAddress(), MacAddress::BroadcastMac(), key_.ip, intf_id, vrf_id);
235 : }
236 :
237 4 : StartTimer(arp_proto->retry_timeout(), ArpProto::RETRY_TIMER_EXPIRED);
238 4 : }
239 :
240 4 : void ArpEntry::AddArpRoute(bool resolved) {
241 4 : if (key_.vrf->GetName() == handler_->agent()->linklocal_vrf_name()) {
242 : // Do not squash existing route entry.
243 : // should be smarter and not replace an existing route.
244 4 : return;
245 : }
246 :
247 4 : Ip4Address ip(key_.ip);
248 4 : const string& vrf_name = key_.vrf->GetName();
249 4 : ArpNHKey nh_key(nh_vrf_->GetName(), ip, false);
250 8 : ArpNH *arp_nh = static_cast<ArpNH *>(handler_->agent()->nexthop_table()->
251 4 : FindActiveEntry(&nh_key));
252 :
253 4 : MacAddress mac = mac_address();
254 4 : if (arp_nh && arp_nh->GetResolveState() &&
255 0 : mac.CompareTo(arp_nh->GetMac()) == 0) {
256 : // MAC address unchanged, ignore
257 0 : if (!IsDerived()) {
258 0 : return;
259 : } else {
260 : /* Return if the route is already existing */
261 : InetUnicastRouteKey *rt_key = new InetUnicastRouteKey(
262 0 : handler_->agent()->local_peer(), vrf_name, ip, 32);
263 0 : AgentRoute *entry = key_.vrf->GetInet4UnicastRouteTable()->
264 0 : FindActiveEntry(rt_key);
265 0 : delete rt_key;
266 0 : if (entry) {
267 0 : return;
268 : }
269 0 : resolved = true;
270 : }
271 : }
272 :
273 4 : ARP_TRACE(Trace, "Add", ip.to_string(), vrf_name, mac.ToString());
274 4 : AgentRoute *entry = key_.vrf->GetInet4UnicastRouteTable()->FindLPM(ip);
275 :
276 4 : bool policy = false;
277 4 : SecurityGroupList sg;
278 4 : TagList tag;
279 4 : VnListType vn_list;
280 : const NextHop *anh;
281 4 : if (entry && (anh = entry->GetActiveNextHop()) != NULL) {
282 4 : policy = anh->PolicyEnabled();
283 4 : sg = entry->GetActivePath()->sg_list();
284 4 : tag = entry->GetActivePath()->tag_list();
285 4 : vn_list = entry->GetActivePath()->dest_vn_list();
286 : }
287 :
288 4 : const Interface *itf = handler_->agent()->GetArpProto()->ip_fabric_interface();
289 4 : if (interface_->type() == Interface::PHYSICAL) {
290 0 : itf = interface_.get();
291 : }
292 4 : if (interface_->type() == Interface::VM_INTERFACE) {
293 : const VmInterface *vintf =
294 4 : static_cast<const VmInterface *>(interface_.get());
295 4 : if (vintf->vmi_type() == VmInterface::VHOST) {
296 8 : for (InterfaceList::size_type i = 0; i != vintf->parent_list().size(); i++) {
297 4 : itf = vintf->parent_list()[i];
298 8 : handler_->agent()->fabric_inet4_unicast_table()->ArpRoute(
299 : DBRequest::DB_ENTRY_ADD_CHANGE, vrf_name, ip, mac,
300 4 : nh_vrf_->GetName(), *itf, resolved, 32, policy,
301 : vn_list, sg, tag);
302 : }
303 4 : return;
304 : }
305 : }
306 :
307 0 : handler_->agent()->fabric_inet4_unicast_table()->ArpRoute(
308 : DBRequest::DB_ENTRY_ADD_CHANGE, vrf_name, ip, mac,
309 0 : nh_vrf_->GetName(), *itf, resolved, 32, policy,
310 : vn_list, sg, tag);
311 16 : }
312 :
313 2 : bool ArpEntry::DeleteArpRoute() {
314 2 : if (key_.vrf->GetName() == handler_->agent()->linklocal_vrf_name()) {
315 0 : return true;
316 : }
317 :
318 2 : Ip4Address ip(key_.ip);
319 2 : const string& vrf_name = key_.vrf->GetName();
320 2 : ArpNHKey nh_key(nh_vrf_->GetName(), ip, false);
321 4 : ArpNH *arp_nh = static_cast<ArpNH *>(handler_->agent()->nexthop_table()->
322 2 : FindActiveEntry(&nh_key));
323 2 : if (!arp_nh)
324 0 : return true;
325 :
326 2 : MacAddress mac = mac_address();
327 2 : ARP_TRACE(Trace, "Delete", ip.to_string(), vrf_name, mac.ToString());
328 2 : if (IsDerived()) {
329 : //Just enqueue a delete, no need to mark nexthop invalid
330 0 : InetUnicastAgentRouteTable::Delete(handler_->agent()->local_peer(),
331 : vrf_name, ip, 32);
332 0 : return true;
333 : }
334 :
335 6 : handler_->agent()->fabric_inet4_unicast_table()->ArpRoute(
336 2 : DBRequest::DB_ENTRY_DELETE, vrf_name, ip, mac, nh_vrf_->GetName(),
337 2 : *interface_, false, 32, false, Agent::NullStringList(),
338 4 : SecurityGroupList(), TagList());
339 2 : return false;
340 2 : }
341 :
342 0 : void ArpEntry::Resync(bool policy, const VnListType &vnlist,
343 : const SecurityGroupList &sg,
344 : const TagList &tag) {
345 0 : Ip4Address ip(key_.ip);
346 0 : const string& vrf_name = key_.vrf->GetName();
347 0 : ARP_TRACE(Trace, "Resync", ip.to_string(), vrf_name,
348 : mac_address().ToString());
349 0 : handler_->agent()->fabric_inet4_unicast_table()->ArpRoute(
350 0 : DBRequest::DB_ENTRY_ADD_CHANGE, key_.vrf->GetName(), ip,
351 0 : mac_address_, nh_vrf_->GetName(), *interface_, IsResolved(),
352 : 32, policy, vnlist, sg, tag);
353 0 : }
|