Skip to content

Commit 0bb249e

Browse files
authored
Merge pull request #1269 from alfred-bratterud/dev
IP4: experimental loopback / VIP, mock of NIC to unit test IP-stack
2 parents 345945f + 179b79b commit 0bb249e

12 files changed

Lines changed: 656 additions & 58 deletions

File tree

api/net/inet.hpp

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#define NET_INET_HPP
2020

2121
#include <chrono>
22+
#include <unordered_set>
2223

2324
#include <net/inet_common.hpp>
2425
#include <hw/mac_addr.hpp>
@@ -48,6 +49,7 @@ namespace net {
4849

4950
template <typename IPv>
5051
using resolve_func = delegate<void(typename IPv::addr)>;
52+
using Vip_list = std::unordered_set<typename IPV::addr>;
5153

5254
///
5355
/// NETWORK CONFIGURATION
@@ -85,19 +87,37 @@ namespace net {
8587
/** Use DHCP to configure this interface */
8688
virtual void negotiate_dhcp(double timeout = 10.0, dhcp_timeout_func = nullptr) = 0;
8789

90+
/** Get a list of virtual IP4 addresses assigned to this interface */
91+
virtual const Vip_list virtual_ips() const = 0;
92+
93+
/** Check if an IP is a (possibly virtual) loopback address */
94+
virtual bool is_loopback(typename IPV::addr a) const = 0;
95+
96+
/** Add an IP address as a virtual loopback IP */
97+
virtual void add_vip(typename IPV::addr a) = 0;
98+
99+
/** Remove an IP address from the virtual loopback IP list */
100+
virtual void remove_vip(typename IPV::addr a) = 0;
101+
102+
/** Determine the appropriate source address for a destination. */
103+
virtual typename IPV::addr get_source_addr(typename IPV::addr dest) = 0;
104+
105+
/** Determine if an IP address is a valid source address for this stack */
106+
virtual bool is_valid_source(typename IPV::addr) = 0;
107+
88108

89109
///
90110
/// PROTOCOL OBJECTS
91111
///
92112

93113
/** Get the IP protocol object for this interface */
94-
virtual IPV& ip_obj() = 0;
114+
virtual IPV& ip_obj() = 0;
95115

96116
/** Get the TCP protocol object for this interface */
97-
virtual TCP& tcp() = 0;
117+
virtual TCP& tcp() = 0;
98118

99119
/** Get the UDP protocol object for this interface */
100-
virtual UDP& udp() = 0;
120+
virtual UDP& udp() = 0;
101121

102122
/** Get the ICMP protocol object for this interface */
103123
virtual ICMPv4& icmp() = 0;
@@ -122,13 +142,13 @@ namespace net {
122142
///
123143

124144
/** Get the network interface device */
125-
virtual hw::Nic& nic() = 0;
145+
virtual hw::Nic& nic() = 0;
126146

127147
/** Get interface name for this interface **/
128-
virtual std::string ifname() const = 0;
148+
virtual std::string ifname() const = 0;
129149

130150
/** Get linklayer address for this interface **/
131-
virtual MAC::Addr link_addr() = 0;
151+
virtual MAC::Addr link_addr() = 0;
132152

133153
/** Add cache entry to the link / IP address cache */
134154
virtual void cache_link_addr(typename IPV::addr, MAC::Addr) = 0;
@@ -137,7 +157,7 @@ namespace net {
137157
virtual void flush_link_cache() = 0;
138158

139159
/** Set the regular interval for link address cache flushing */
140-
virtual void set_link_cache_flush_interval(std::chrono::minutes);
160+
virtual void set_link_cache_flush_interval(std::chrono::minutes) = 0;
141161

142162

143163
///

api/net/inet4.hpp

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,16 @@
1818
#ifndef NET_INET4_HPP
1919
#define NET_INET4_HPP
2020

21+
#include <vector>
22+
#include <unordered_set>
23+
2124
#include "inet.hpp"
2225
#include "ip4/arp.hpp"
2326
#include "ip4/ip4.hpp"
2427
#include "ip4/udp.hpp"
2528
#include "ip4/icmp4.hpp"
2629
#include "dns/client.hpp"
2730
#include "tcp/tcp.hpp"
28-
#include <vector>
2931
#include "super_stack.hpp"
3032

3133
namespace net {
@@ -35,6 +37,9 @@ namespace net {
3537
/** A complete IP4 network stack */
3638
class Inet4 : public Inet<IP4>{
3739
public:
40+
41+
using Vip4_list = std::unordered_set<IP4::addr>;
42+
3843
std::string ifname() const override
3944
{ return nic_.device_name(); }
4045

@@ -122,7 +127,6 @@ namespace net {
122127
return ip_packet;
123128
}
124129

125-
126130
IP_packet_factory ip_packet_factory() override
127131
{ return IP_packet_factory{this, &Inet4::create_ip_packet}; }
128132

@@ -243,10 +247,50 @@ namespace net {
243247
return stack<N>();
244248
}
245249

246-
private:
250+
/** Add virtual IP4 address as loopback */
251+
const Vip4_list virtual_ips() const noexcept override
252+
{ return vip4s_; }
253+
254+
/** Check if IP4 address is virtual loopback */
255+
bool is_loopback(IP4::addr a) const override
256+
{
257+
return a.is_loopback()
258+
or vip4s_.find(a) != vip4s_.end();
259+
}
260+
261+
/** Add IP4 address as virtual loopback */
262+
void add_vip(IP4::addr a) override
263+
{
264+
if (not is_loopback(a)) {
265+
INFO("Inet4", "Adding virtual IP address %s", a.to_string().c_str());
266+
vip4s_.emplace(a);
267+
}
268+
}
269+
270+
/** Add IP4 address as virtual loopback */
271+
void remove_vip(IP4::addr a) override
272+
{ vip4s_.erase(a); }
273+
274+
IP4::addr get_source_addr(IP4::addr dest) override
275+
{
276+
277+
if (dest.is_loopback())
278+
return {127,0,0,1};
279+
280+
if (is_loopback(dest))
281+
return dest;
282+
283+
return ip_addr();
284+
}
285+
286+
bool is_valid_source(IP4::addr src) override
287+
{ return is_loopback(src) or src == ip_addr(); }
288+
247289
/** Initialize with ANY_ADDR */
248290
Inet4(hw::Nic& nic);
249291

292+
private:
293+
250294
void process_sendq(size_t);
251295
// delegates registered to get signalled about free packets
252296
std::vector<transmit_avail_delg> tqa;
@@ -256,6 +300,8 @@ namespace net {
256300
IP4::addr gateway_;
257301
IP4::addr dns_server;
258302

303+
Vip4_list vip4s_ = {{127,0,0,1}};
304+
259305
// This is the actual stack
260306
hw::Nic& nic_;
261307
Arp arp_;

api/net/ip4/addr.hpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,23 @@ struct Addr {
316316
std::string to_string() const
317317
{ return str(); }
318318

319+
/**
320+
* RFC-1122 / IANA IP4 address space defines 127.* as loopback
321+
**/
322+
bool is_loopback() const noexcept
323+
{ return part(3) == 127; }
324+
325+
/**
326+
* Determine if an address is a-priori illegal as source address in *all* cases.
327+
*
328+
* @note: The class E range 240/4 for "future use" is not illegal here
329+
* @note: RFC-1122 prohibits 0.0.0.0 as source, but with exceptions
330+
*/
331+
bool is_illegal_src() const noexcept {
332+
return (part(3) >= 224 and part(3) < 240) // Multicast
333+
or (part(0) == 255); // Limited and directed broadcast
334+
}
335+
319336
/* Data member */
320337
uint32_t whole;
321338
} __attribute__((packed)); //< struct Addr

api/net/ip4/ip4.hpp

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,23 @@ namespace net {
3030
/** IP4 layer */
3131
class IP4 {
3232
public:
33+
34+
enum class Drop_reason
35+
{ None, Bad_source, Bad_destination, Wrong_version, Wrong_checksum,
36+
Unknown_proto, TTL0 };
37+
38+
enum class Direction
39+
{ Upstream, Downstream };
40+
41+
3342
using Stack = Inet<IP4>;
3443
using addr = ip4::Addr;
3544
using header = ip4::Header;
3645
using IP_packet = PacketIP4;
3746
using IP_packet_ptr = std::unique_ptr<IP_packet>;
3847
using downstream_arp = delegate<void(Packet_ptr, IP4::addr)>;
48+
using Packet_filter = delegate<IP_packet_ptr(IP_packet_ptr)>;
49+
using drop_handler = delegate<void(IP_packet_ptr, Direction, Drop_reason)>;
3950

4051
/** Initialize. Sets a dummy linklayer out. */
4152
explicit IP4(Stack&) noexcept;
@@ -69,14 +80,25 @@ namespace net {
6980
void set_tcp_handler(upstream s)
7081
{ tcp_handler_ = s; }
7182

83+
/** Set packet dropped handler */
84+
void set_drop_handler(drop_handler s)
85+
{ drop_handler_ = s; }
86+
7287
/** Set handler for packets not addressed to this interface (upstream) */
7388
void set_packet_forwarding(Stack::Forward_delg fwd)
7489
{ forward_packet_ = fwd; }
7590

7691
/** Set linklayer out (downstream) */
7792
void set_linklayer_out(downstream_arp s)
78-
{ linklayer_out_ = s; };
93+
{ linklayer_out_ = s; }
7994

95+
/** Assign function to determine which upstream packets gets filtered */
96+
void set_upstream_filter(Packet_filter f)
97+
{ upstream_filter_ = f; }
98+
99+
/** Assign function to determine which downstream packets gets filtered */
100+
void set_downstream_filter(Packet_filter f)
101+
{ downstream_filter_ = f; }
80102

81103
//
82104
// Delegate getters
@@ -120,6 +142,7 @@ namespace net {
120142
return stack_.ip_addr();
121143
}
122144

145+
123146
/**
124147
* Stats getters
125148
**/
@@ -132,6 +155,15 @@ namespace net {
132155
uint64_t get_packets_dropped()
133156
{ return packets_dropped_; }
134157

158+
/** Default upstream packet filter */
159+
IP_packet_ptr filter_upstream(IP_packet_ptr packet);
160+
161+
/** Default downstream packet filter */
162+
IP_packet_ptr filter_downstream(IP_packet_ptr packet);
163+
164+
165+
166+
135167
private:
136168
/** Stats */
137169
uint64_t& packets_rx_;
@@ -151,9 +183,19 @@ namespace net {
151183
/** Packet forwarding */
152184
Stack::Forward_delg forward_packet_;
153185

154-
}; //< class IP4
186+
/** Packet filters */
187+
Packet_filter upstream_filter_;
188+
Packet_filter downstream_filter_;
155189

156190

191+
/** All dropped packets go here */
192+
drop_handler drop_handler_;
193+
194+
/** Drop a packet, calling drop handler if set */
195+
IP_packet_ptr drop(IP_packet_ptr ptr, Direction direction, Drop_reason reason);
196+
197+
}; //< class IP4
198+
157199
} //< namespace net
158200

159201
#endif

api/net/ip4/packet_ip4.hpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@ namespace net {
3939

4040
/** Get IP protocol version field. Must be 4 (RFC 1122) */
4141
uint8_t ip_version() const noexcept
42-
{ return ip_header().version_ihl & 0x0f; }
42+
{ return (ip_header().version_ihl >> 4) & 0xf; }
43+
44+
bool is_ipv4() const noexcept
45+
{ return (ip_header().version_ihl & 0xf0) == 0x40; }
4346

4447
/** Get IP header length field as-is. */
4548
uint8_t ip_ihl() const noexcept
@@ -71,7 +74,7 @@ namespace net {
7174

7275
/** Get Fragment offset field */
7376
uint16_t ip_frag_offs() const noexcept
74-
{ return ntohs(ip_header().frag_off_flags) | 0xe; }
77+
{ return ntohs(ip_header().frag_off_flags) & 0xe; }
7578

7679
/** Get Time-To-Live field */
7780
uint8_t ip_ttl() const noexcept
@@ -104,6 +107,9 @@ namespace net {
104107
uint16_t ip_capacity() const noexcept
105108
{ return capacity() - ip_header_length(); }
106109

110+
/** Compute IP header checksum on header as-is */
111+
uint16_t compute_checksum() noexcept
112+
{ return net::checksum(&ip_header(), ip_header_length()); };
107113

108114

109115
//
@@ -208,6 +214,8 @@ namespace net {
208214
hdr.frag_off_flags = 0;
209215
hdr.ttl = DEFAULT_TTL;
210216
hdr.protocol = static_cast<uint8_t>(proto);
217+
hdr.check = 0;
218+
hdr.tot_len = 0x1400; // Big-endian 20
211219
increment_data_end(sizeof(IP4::header));
212220
}
213221

@@ -219,7 +227,6 @@ namespace net {
219227
return {ip_data_ptr(), ip_data_length()};
220228
}
221229

222-
223230
protected:
224231

225232
/** Get pointer to IP data */

0 commit comments

Comments
 (0)