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 <stdint.h>
7 : #include <math.h>
8 : #include "vr_defs.h"
9 : #include "init/agent_param.h"
10 : #include "oper/route_common.h"
11 : #include "oper/operdb_init.h"
12 : #include "oper/path_preference.h"
13 : #include "pkt/pkt_init.h"
14 : #include "services/arp_proto.h"
15 : #include "services/services_init.h"
16 : #include "services/services_sandesh.h"
17 : #include "mac_learning/mac_learning_proto.h"
18 :
19 3098 : ArpHandler::ArpHandler(Agent *agent, boost::shared_ptr<PktInfo> info,
20 3098 : boost::asio::io_context &io)
21 3098 : : ProtoHandler(agent, info, io), arp_(NULL), arp_tpa_(0) {
22 3098 : refcount_ = 0;
23 3098 : }
24 :
25 3834 : ArpHandler::~ArpHandler() {
26 3834 : }
27 :
28 736 : bool ArpHandler::Run() {
29 :
30 : // Process ARP only when the IP Fabric interface is configured
31 :
32 736 : assert(agent());
33 736 : assert(agent()->GetArpProto());
34 736 : ArpProto *arp_proto = agent()->GetArpProto();
35 :
36 736 : if (agent()->GetArpProto()->ip_fabric_interface() == NULL) {
37 0 : arp_proto->IncrementStatsIPFabricNotInst();
38 0 : delete pkt_info_->ipc;
39 0 : return true;
40 : }
41 :
42 736 : switch(pkt_info_->type) {
43 736 : case PktType::MESSAGE:
44 736 : return HandleMessage();
45 :
46 0 : default:
47 0 : return HandlePacket();
48 : }
49 : }
50 :
51 0 : bool ArpHandler::HandlePacket() {
52 0 : ArpProto *arp_proto = agent()->GetArpProto();
53 : uint16_t arp_cmd;
54 0 : if (pkt_info_->ip) {
55 0 : arp_tpa_ = ntohl(pkt_info_->ip->ip_dst.s_addr);
56 0 : arp_cmd = ARPOP_REQUEST;
57 0 : } else if (pkt_info_->arp) {
58 0 : arp_ = pkt_info_->arp;
59 0 : if ((ntohs(arp_->ea_hdr.ar_hrd) != ARPHRD_ETHER) ||
60 0 : (ntohs(arp_->ea_hdr.ar_pro) != ETHERTYPE_IP) ||
61 0 : (arp_->ea_hdr.ar_hln != ETHER_ADDR_LEN) ||
62 0 : (arp_->ea_hdr.ar_pln != IPv4_ALEN)) {
63 0 : arp_proto->IncrementStatsInvalidPackets();
64 0 : ARP_TRACE(Error, "Received Invalid ARP packet");
65 0 : return true;
66 : }
67 0 : arp_cmd = ntohs(arp_->ea_hdr.ar_op);
68 : union {
69 : uint8_t data[sizeof(in_addr_t)];
70 : in_addr_t addr;
71 : } bytes;
72 0 : memcpy(bytes.data, arp_->arp_tpa, sizeof(in_addr_t));
73 0 : in_addr_t tpa = ntohl(bytes.addr);
74 0 : memcpy(bytes.data, arp_->arp_spa, sizeof(in_addr_t));
75 0 : in_addr_t spa = ntohl(bytes.addr);
76 0 : if (arp_cmd == ARPOP_REQUEST)
77 0 : arp_tpa_ = tpa;
78 : else
79 0 : arp_tpa_ = spa;
80 :
81 : // if it is our own, ignore
82 0 : if (arp_tpa_ == agent()->router_id().to_ulong()) {
83 0 : arp_proto->IncrementStatsGratuitous();
84 0 : return true;
85 : }
86 :
87 0 : if (tpa == spa || spa == 0) {
88 0 : arp_cmd = GRATUITOUS_ARP;
89 : }
90 : } else {
91 0 : arp_proto->IncrementStatsInvalidPackets();
92 0 : ARP_TRACE(Error, "ARP : Received Invalid packet");
93 0 : return true;
94 : }
95 :
96 : const Interface *itf =
97 0 : agent()->interface_table()->FindInterface(GetInterfaceIndex());
98 0 : if (!itf || !itf->IsActive()) {
99 0 : arp_proto->IncrementStatsInvalidInterface();
100 0 : ARP_TRACE(Error, "Received ARP packet from invalid / inactive interface");
101 0 : return true;
102 : }
103 :
104 0 : const VrfEntry *vrf = agent()->vrf_table()->FindVrfFromId(pkt_info_->vrf);
105 0 : if (!vrf || !vrf->IsActive()) {
106 0 : arp_proto->IncrementStatsInvalidVrf();
107 0 : ARP_TRACE(Error, "ARP : AgentHdr " + itf->name() +
108 : " has no / inactive VRF ");
109 0 : return true;
110 : }
111 0 : const VrfEntry *nh_vrf = itf->vrf();
112 0 : if (!nh_vrf || !nh_vrf->IsActive()) {
113 0 : arp_proto->IncrementStatsInvalidVrf();
114 0 : ARP_TRACE(Error, "ARP : Interface " + itf->name() +
115 : " has no / inactive VRF");
116 0 : return true;
117 : }
118 :
119 : // if broadcast ip, return
120 0 : Ip4Address arp_addr(arp_tpa_);
121 0 : if (arp_tpa_ == 0xFFFFFFFF || !arp_tpa_) {
122 0 : arp_proto->IncrementStatsInvalidAddress();
123 0 : ARP_TRACE(Error, "ARP : ignoring broadcast address" +
124 : arp_addr.to_string());
125 0 : return true;
126 : }
127 :
128 : //Look for subnet broadcast
129 : AgentRoute *route =
130 : static_cast<InetUnicastAgentRouteTable *>(vrf->
131 0 : GetInet4UnicastRouteTable())->FindLPM(arp_addr);
132 0 : if (route) {
133 0 : const NextHop *anh = route->GetActiveNextHop();
134 0 : if (route->is_multicast()) {
135 0 : arp_proto->IncrementStatsInvalidAddress();
136 0 : ARP_TRACE(Error, "ARP : ignoring multicast address" +
137 : arp_addr.to_string());
138 0 : return true;
139 : }
140 0 : if (anh == NULL) {
141 0 : arp_proto->IncrementStatsInvalidAddress();
142 0 : ARP_TRACE(Error, "ARP : no active nexthop" +
143 : arp_addr.to_string());
144 0 : return true;
145 : }
146 0 : if(anh->GetType() == NextHop::RESOLVE) {
147 0 : const ResolveNH *nh =
148 : static_cast<const ResolveNH *>(anh);
149 0 : itf = nh->get_interface();
150 0 : nh_vrf = itf->vrf();
151 : }
152 : }
153 :
154 0 : ArpKey key(arp_tpa_, vrf);
155 0 : ArpEntry *entry = arp_proto->FindArpEntry(key);
156 :
157 0 : if (nh_vrf->forwarding_vrf()) {
158 0 : nh_vrf = nh_vrf->forwarding_vrf();
159 : }
160 :
161 0 : switch (arp_cmd) {
162 0 : case ARPOP_REQUEST: {
163 0 : arp_proto->IncrementStatsArpReq();
164 0 : arp_proto->IncrementStatsArpRequest(itf->id());
165 0 : if (entry) {
166 0 : entry->HandleArpRequest();
167 0 : return true;
168 : } else {
169 0 : entry = new ArpEntry(io_, this, key, nh_vrf, ArpEntry::INITING,
170 0 : itf);
171 0 : if (arp_proto->AddArpEntry(entry) == false) {
172 0 : delete entry;
173 0 : return true;
174 : }
175 0 : entry->HandleArpRequest();
176 0 : return false;
177 : }
178 : }
179 :
180 0 : case ARPOP_REPLY: {
181 0 : arp_proto->IncrementStatsArpReplies();
182 0 : arp_proto->IncrementStatsArpReply(itf->id());
183 0 : if (itf->type() == Interface::VM_INTERFACE) {
184 : uint32_t ip;
185 0 : memcpy(&ip, arp_->arp_spa, sizeof(ip));
186 0 : ip = ntohl(ip);
187 : /* Enqueue a request to trigger state machine. The prefix-len
188 : * of 32 passed below is not used. We do LPMFind on IP to
189 : * figure out the actual prefix-len inside
190 : * EnqueueTrafficSeen
191 : */
192 : agent()->oper_db()->route_preference_module()->
193 0 : EnqueueTrafficSeen(Ip4Address(ip), 32, itf->id(),
194 : vrf->vrf_id(),
195 0 : MacAddress(arp_->arp_sha));
196 0 : arp_proto->HandlePathPreferenceArpReply(vrf, itf->id(),
197 0 : Ip4Address(ip));
198 :
199 0 : if(entry) {
200 0 : entry->HandleArpReply(MacAddress(arp_->arp_sha));
201 : }
202 0 : return true;
203 : }
204 0 : if(entry) {
205 0 : entry->HandleArpReply(MacAddress(arp_->arp_sha));
206 0 : return true;
207 : } else {
208 0 : entry = new ArpEntry(io_, this, key, nh_vrf, ArpEntry::INITING,
209 0 : itf);
210 0 : if (arp_proto->AddArpEntry(entry) == false) {
211 0 : delete entry;
212 0 : return true;
213 : }
214 0 : entry->HandleArpReply(MacAddress(arp_->arp_sha));
215 0 : arp_ = NULL;
216 0 : return false;
217 : }
218 : }
219 :
220 0 : case GRATUITOUS_ARP: {
221 0 : arp_proto->IncrementStatsGratuitous();
222 0 : if (itf->type() == Interface::VM_INTERFACE) {
223 : uint32_t ip;
224 0 : memcpy(&ip, arp_->arp_spa, sizeof(ip));
225 0 : ip = ntohl(ip);
226 : //Enqueue a request to trigger state machine
227 : agent()->oper_db()->route_preference_module()->
228 0 : EnqueueTrafficSeen(Ip4Address(ip), 32, itf->id(),
229 : vrf->vrf_id(),
230 0 : MacAddress(arp_->arp_sha));
231 0 : return true;
232 0 : } else if (entry) {
233 0 : entry->HandleArpReply(MacAddress(arp_->arp_sha));
234 0 : return true;
235 : } else {
236 : // ignore gratuitous ARP when entry is not present in cache
237 0 : return true;
238 : }
239 : }
240 :
241 0 : default:
242 0 : ARP_TRACE(Error, "Received Invalid ARP command : " +
243 : integerToString(arp_cmd));
244 0 : return true;
245 : }
246 : }
247 :
248 : /* This API is invoked from the following paths
249 : - NextHop notification for ARP_NH
250 : - ARP Timer expiry
251 : - Sending Gratituous ARP for Receive Nexthops
252 : In all these above paths we expect route_vrf and nh_vrf for ArpRoute to
253 : be same
254 : */
255 736 : bool ArpHandler::HandleMessage() {
256 736 : bool ret = true;
257 736 : ArpProto::ArpIpc *ipc = static_cast<ArpProto::ArpIpc *>(pkt_info_->ipc);
258 736 : ArpProto *arp_proto = agent()->GetArpProto();
259 736 : switch(pkt_info_->ipc->cmd) {
260 4 : case ArpProto::ARP_RESOLVE: {
261 4 : ArpEntry *entry = arp_proto->FindArpEntry(ipc->key);
262 4 : if (!entry) {
263 4 : entry = new ArpEntry(io_, this, ipc->key, ipc->key.vrf,
264 2 : ArpEntry::INITING, ipc->interface_.get());
265 2 : if (arp_proto->AddArpEntry(entry) == false) {
266 0 : delete entry;
267 0 : break;
268 : }
269 2 : ret = false;
270 : }
271 4 : arp_proto->IncrementStatsArpReq();
272 4 : arp_proto->IncrementStatsArpRequest(ipc->interface_->id());
273 4 : entry->HandleArpRequest();
274 4 : break;
275 : }
276 :
277 726 : case ArpProto::ARP_SEND_GRATUITOUS: {
278 726 : bool key_valid = false;
279 : ArpProto::GratuitousArpIterator it =
280 726 : arp_proto->GratuitousArpEntryIterator(ipc->key, &key_valid);
281 726 : if (key_valid && !ipc->interface_->IsDeleted()) {
282 541 : ArpEntry *entry = NULL;
283 541 : ArpProto::ArpEntrySet::iterator sit = it->second.begin();
284 542 : for (; sit != it->second.end(); sit++) {
285 420 : entry = *sit;
286 420 : if (entry->get_interface() == ipc->interface_.get())
287 419 : break;
288 : }
289 541 : if (sit == it->second.end()) {
290 244 : entry = new ArpEntry(io_, this, ipc->key, ipc->key.vrf,
291 122 : ArpEntry::ACTIVE, ipc->interface_.get());
292 122 : it->second.insert(entry);
293 122 : ret = false;
294 : }
295 541 : if (entry)
296 541 : entry->SendGratuitousArp();
297 541 : break;
298 : }
299 : }
300 :
301 : case ArpProto::ARP_DELETE: {
302 187 : EntryDelete(ipc->key);
303 187 : break;
304 : }
305 :
306 2 : case ArpProto::RETRY_TIMER_EXPIRED: {
307 2 : ArpEntry *entry = arp_proto->FindArpEntry(ipc->key);
308 2 : if (entry && !entry->RetryExpiry()) {
309 0 : arp_proto->DeleteArpEntry(entry);
310 : }
311 2 : break;
312 : }
313 :
314 0 : case ArpProto::AGING_TIMER_EXPIRED: {
315 0 : ArpEntry *entry = arp_proto->FindArpEntry(ipc->key);
316 0 : if (entry && !entry->AgingExpiry()) {
317 0 : arp_proto->DeleteArpEntry(entry);
318 : }
319 0 : break;
320 : }
321 :
322 2 : case ArpProto::GRATUITOUS_TIMER_EXPIRED: {
323 : ArpEntry *entry =
324 2 : arp_proto->GratuitousArpEntry(ipc->key, ipc->interface_.get());
325 2 : if (entry && entry->retry_count() <= ArpProto::kGratRetries) {
326 1 : entry->SendGratuitousArp();
327 : } else {
328 : // Need to validate deleting the Arp entry upon fabric vrf Delete only
329 1 : if (ipc->key.vrf->GetName() != agent()->fabric_vrf_name()) {
330 1 : arp_proto->DeleteGratuitousArpEntry(entry);
331 : }
332 : }
333 2 : break;
334 : }
335 :
336 0 : default:
337 0 : ARP_TRACE(Error, "Received Invalid internal ARP message : " +
338 : integerToString(pkt_info_->ipc->cmd));
339 0 : break;
340 : }
341 736 : delete ipc;
342 736 : return ret;
343 : }
344 :
345 187 : void ArpHandler::EntryDelete(ArpKey &key) {
346 187 : ArpProto *arp_proto = agent()->GetArpProto();
347 187 : ArpEntry *entry = arp_proto->FindArpEntry(key);
348 187 : if (entry) {
349 2 : arp_proto->DeleteArpEntry(entry);
350 : // this request comes when ARP NH is deleted; nothing more to do
351 : }
352 187 : }
353 :
354 2204 : uint16_t ArpHandler::ArpHdr(const MacAddress &smac, in_addr_t sip,
355 : const MacAddress &tmac, in_addr_t tip, uint16_t op) {
356 2204 : arp_->ea_hdr.ar_hrd = htons(ARPHRD_ETHER);
357 2204 : arp_->ea_hdr.ar_pro = htons(0x800);
358 2204 : arp_->ea_hdr.ar_hln = ETHER_ADDR_LEN;
359 2204 : arp_->ea_hdr.ar_pln = IPv4_ALEN;
360 2204 : arp_->ea_hdr.ar_op = htons(op);
361 2204 : smac.ToArray(arp_->arp_sha, sizeof(arp_->arp_sha));
362 2204 : sip = htonl(sip);
363 2204 : memcpy(arp_->arp_spa, &sip, sizeof(in_addr_t));
364 2204 : tmac.ToArray(arp_->arp_tha, sizeof(arp_->arp_tha));
365 2204 : tip = htonl(tip);
366 2204 : memcpy(arp_->arp_tpa, &tip, sizeof(in_addr_t));
367 2204 : return sizeof(ether_arp);
368 : }
369 :
370 2204 : void ArpHandler::SendArp(uint16_t op, const MacAddress &smac, in_addr_t sip,
371 : const MacAddress &tmac, const MacAddress &dmac,
372 : in_addr_t tip, uint32_t itf, uint32_t vrf) {
373 :
374 2204 : if (pkt_info_->packet_buffer() == NULL) {
375 113 : pkt_info_->AllocPacketBuffer(agent(), PktHandler::ARP, ARP_TX_BUFF_LEN,
376 : 0);
377 : }
378 :
379 2204 : char *buf = (char *)pkt_info_->packet_buffer()->data();
380 2204 : memset(buf, 0, pkt_info_->packet_buffer()->data_len());
381 2204 : pkt_info_->eth = (struct ether_header *)buf;
382 2204 : int l2_len = EthHdr(buf, pkt_info_->packet_buffer()->data_len(),
383 : itf, smac, dmac, ETHERTYPE_ARP);
384 2204 : arp_ = pkt_info_->arp = (ether_arp *) (buf + l2_len);
385 2204 : arp_tpa_ = tip;
386 :
387 2204 : ArpHdr(smac, sip, tmac, tip, op);
388 2204 : pkt_info_->set_len(l2_len + sizeof(ether_arp));
389 :
390 2204 : Send(itf, vrf, AgentHdr::TX_SWITCH, PktHandler::ARP);
391 2204 : }
392 :
393 1700 : void ArpHandler::SendArpRequestByPlen(const VmInterface *vm_interface, const MacAddress &smac,
394 : const ArpPathPreferenceState *data,
395 : const Ip4Address &tpa) {
396 1700 : Ip4Address service_ip = vm_interface->GetServiceIp(data->ip()).to_v4();
397 1700 : bool aap_ip = vm_interface->MatchAapIp(data->ip(), data->plen());
398 : #if 0
399 : MacAddress mac = agent()->mac_learning_proto()->
400 : GetMacIpLearningTable()->GetPairedMacAddress(
401 : vm_interface->vrf()->vrf_id(),
402 : data->ip());
403 : #endif
404 1700 : MacAddress mac = data->mac();
405 :
406 1700 : if (mac == MacAddress()) {
407 798 : mac = vm_interface->vm_mac();
408 : }
409 :
410 1700 : if (data->plen() == Address::kMaxV4PrefixLen) {
411 3400 : SendArp(ARPOP_REQUEST, smac, service_ip.to_ulong(), MacAddress(),
412 0 : ((aap_ip) ? MacAddress::BroadcastMac(): mac),
413 1700 : data->ip().to_v4().to_ulong(), vm_interface->id(), data->vrf_id());
414 1700 : agent()->GetArpProto()->IncrementStatsVmArpReq();
415 : } else {
416 0 : if (!tpa.is_unspecified()) {
417 0 : SendArp(ARPOP_REQUEST, smac, service_ip.to_ulong(),
418 0 : MacAddress(), ((aap_ip) ? MacAddress::BroadcastMac(): mac),
419 0 : tpa.to_ulong(), vm_interface->id(), data->vrf_id());
420 0 : agent()->GetArpProto()->IncrementStatsVmArpReq();
421 0 : return;
422 : }
423 : /* Loop through all the IPs for the prefix-len and send Arp for each
424 : * IP*/
425 0 : uint8_t diff_plen = Address::kMaxV4PrefixLen - data->plen();
426 0 : uint32_t num_addresses = pow(2, diff_plen);
427 0 : const uint32_t &max_addresses = MaxArpProbeAddresses();
428 0 : if (num_addresses > max_addresses) {
429 0 : num_addresses = max_addresses;
430 : /* When min_aap_prefix_len (configured by user in agent config file)
431 : * we need to visit all addresses specified by user, because
432 : * base address in this case will be formed by prefix-len lower
433 : * than min_aap_prefix_len. This prefix len is determined by
434 : * data->plen(). The loop below which goes through all the
435 : * addresses will visit 2 addresses less after discounting base
436 : * address and broadcast address. Because base address in this case
437 : * is formed by prefix-len lower than min_aap_prefix_len, we should
438 : * not discount the two addresses. Hence increment by 2.
439 : */
440 0 : num_addresses += 2;
441 : }
442 0 : uint32_t base_addr = data->ip().to_v4().to_ulong();
443 0 : for (uint32_t i = 1; i < num_addresses; ++i) {
444 0 : uint32_t addr = base_addr + i;
445 0 : SendArp(ARPOP_REQUEST, smac, service_ip.to_ulong(),
446 0 : MacAddress(), ((aap_ip) ? MacAddress::BroadcastMac(): mac),
447 : addr, vm_interface->id(), data->vrf_id());
448 0 : agent()->GetArpProto()->IncrementStatsVmArpReq();
449 : }
450 : }
451 : }
452 :
453 0 : uint32_t ArpHandler::MaxArpProbeAddresses() const {
454 0 : uint32_t diff_plen = Address::kMaxV4PrefixLen -
455 0 : agent()->params()->min_aap_prefix_len();
456 0 : return pow(2, diff_plen);
457 : }
458 :
459 124 : void intrusive_ptr_add_ref(const ArpHandler *p) {
460 124 : p->refcount_++;
461 124 : }
462 :
463 124 : void intrusive_ptr_release(const ArpHandler *p) {
464 248 : if (p->refcount_.fetch_sub(1) == 1) {
465 124 : delete p;
466 : }
467 124 : }
|