-
Notifications
You must be signed in to change notification settings - Fork 0
/
arp-cache.hpp
221 lines (179 loc) · 6.03 KB
/
arp-cache.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2017 Alexander Afanasyev
*
* This program is free software: you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by the Free Software Foundation, either version
* 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
/*
This file defines an ARP cache with ARP request queue and ARP cache entries
The ARP cache entries hold IP->MAC mappings and are timed out every SR_ARPCACHE_TO seconds.
--
The handle_arpreq() function is a function you should write, and it should
handle sending ARP requests if necessary:
function handle_arpreq(req):
if now - req->timeSent > seconds(1)
if req->nTimesSent >= 5:
send icmp host unreachable to source addr of all pkts waiting
on this request
cache.removeRequest(req)
else:
send arp request
req->timeSent = now
req->nTimesSent++
--
The ARP reply processing code should move entries from the ARP request
queue to the ARP cache:
# When servicing an arp reply that gives us an IP->MAC mapping
req = cache.insertArpEntry(ip, mac)
if req != nullptr:
send all packets on the req->packets linked list
cache.removeRequest(req)
--
To meet the guidelines in the assignment (ARP requests are sent every second
until we send 5 ARP requests, then we send ICMP host unreachable back to
all packets waiting on this ARP request), you must fill out the following
function that is called every second and is defined in sr_arpcache.c:
void
ArpCache::periodicCheckArpRequestsAndCacheEntries() {
for each request on m_arpRequests:
handle_arpreq(request)
}
*/
#ifndef SIMPLE_ROUTER_ARP_CACHE_HPP
#define SIMPLE_ROUTER_ARP_CACHE_HPP
#include "core/protocol.hpp"
#include <list>
#include <mutex>
#include <thread>
#include <chrono>
#include <memory>
namespace simple_router {
class SimpleRouter;
using steady_clock = std::chrono::steady_clock;
using time_point = std::chrono::steady_clock::time_point;
using seconds = std::chrono::seconds;
const seconds SR_ARPCACHE_TO = seconds(30);
const uint32_t MAX_SENT_TIME = 5;
struct PendingPacket
{
Buffer packet; //< A raw Ethernet frame, presumably with the dest MAC empty
std::string iface; //< The outgoing interface
};
struct ArpRequest {
ArpRequest(uint32_t ip)
: ip(ip)
, nTimesSent(0)
{
}
uint32_t ip;
/**
* Last time this ARP request was sent. You should update this. If
* the ARP request was never sent, timeSent == time_point()
*/
time_point timeSent;
/**
* The number of times this request was sent. You should update this.
*/
uint32_t nTimesSent;
std::list<PendingPacket> packets;
};
struct ArpEntry {
Buffer mac;
uint32_t ip = 0; //< IP addr in network byte order
time_point timeAdded;
bool isValid = false;
};
class ArpCache {
public:
ArpCache(SimpleRouter& router);
~ArpCache();
/**
* IMPLEMENT THIS METHOD
*
* This method gets called every second. For each request sent out,
* you should keep checking whether to resend a request or remove it.
*
* Your implementation should follow the following logic
*
* for each request in queued requests:
* handleRequest(request)
*
* for each cache entry in entries:
* if not entry->isValid
* record entry for removal
* remove all entries marked for removal
*/
void
periodicCheckArpRequestsAndCacheEntries();
/**
* Checks if an IP->MAC mapping is in the cache. IP is in network byte order.
* You must free the returned structure if it is not NULL.
*/
std::shared_ptr<ArpEntry>
lookup(uint32_t ip,bool lock);
/**
* Adds an ARP request to the ARP request queue. If the request is already on
* the queue, adds the packet to the linked list of packets for this sr_arpreq
* that corresponds to this ARP request. The packet argument should not be
* freed by the caller.
*
* A pointer to the ARP request is returned; it should not be freed. The caller
* can remove the ARP request from the queue by calling sr_arpreq_destroy.
*/
std::shared_ptr<ArpRequest>
queueRequest(uint32_t ip, const Buffer& packet, const std::string& iface,bool lock);
/*
* Frees all memory associated with this arp request entry. If this arp request
* entry is on the arp request queue, it is removed from the queue.
*/
void
removeRequest(const std::shared_ptr<ArpRequest>& entry);
/**
* This method performs two functions:
*
* 1) Looks up this IP in the request queue. If it is found, returns a pointer
* to the ArpRequest with this IP. Otherwise, returns nullptr.
* 2) Inserts this IP to MAC mapping in the cache, and marks it valid.
*/
std::shared_ptr<ArpRequest>
insertArpEntry(const Buffer& mac, uint32_t ip);
/**
* Prints out the ARP table.
*/
void
dump();
/**
* Clear all entries in ARP cache and requests.
*/
void
clear();
private:
/**
* Thread which sweeps through the cache and invalidates entries that were added
* more than SR_ARPCACHE_TO seconds ago.
*/
void
ticker();
private:
SimpleRouter& m_router;
std::list<std::shared_ptr<ArpEntry>> m_cacheEntries;
std::list<std::shared_ptr<ArpRequest>> m_arpRequests;
volatile bool m_shouldStop;
std::thread m_tickerThread;
mutable std::mutex m_mutex;
friend std::ostream&
operator<<(std::ostream& os, const ArpCache& cache);
};
std::ostream&
operator<<(std::ostream& os, const ArpCache& cache);
} // namespace simple_router
#endif // SIMPLE_ROUTER_ARP_CACHE_HPP