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