diff options
author | Nathan Binkert <binkertn@umich.edu> | 2004-10-23 16:18:44 -0400 |
---|---|---|
committer | Nathan Binkert <binkertn@umich.edu> | 2004-10-23 16:18:44 -0400 |
commit | a7fd7729ab908d8f93b9bbd290d43f1f21695e3d (patch) | |
tree | ba4270879f2e8635f21c6c751c0ffc7bcbe4c6f9 /base | |
parent | 833c5b5ef49b4b0ff6c1736b71b6149feee50cb5 (diff) | |
download | gem5-a7fd7729ab908d8f93b9bbd290d43f1f21695e3d.tar.xz |
flesh out the TCP/IP/Ethernet support
base/refcnt.hh:
reorganize the RefCountingPtr a little bit to make it easier
to derive from
dev/etherpkt.hh:
this doesn't belong here. use the inet.hh stuff
dev/ns_gige.cc:
dev/ns_gige.hh:
use newer features in the tcp/ip/ethernet stuff
--HG--
extra : convert_revision : 32c1953c95655c1f4c70e0d8adedfd94beead624
Diffstat (limited to 'base')
-rw-r--r-- | base/inet.cc | 170 | ||||
-rw-r--r-- | base/inet.hh | 311 | ||||
-rw-r--r-- | base/refcnt.hh | 33 |
3 files changed, 448 insertions, 66 deletions
diff --git a/base/inet.cc b/base/inet.cc index 0b9e32854..eca7238ff 100644 --- a/base/inet.cc +++ b/base/inet.cc @@ -26,6 +26,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <cstdio> #include <sstream> #include <string> @@ -34,29 +35,174 @@ #include "base/inet.hh" using namespace std; +namespace Net { + +EthAddr::EthAddr() +{ + memset(data, 0, ETH_ADDR_LEN); +} + +EthAddr::EthAddr(const uint8_t ea[ETH_ADDR_LEN]) +{ + *data = *ea; +} + +EthAddr::EthAddr(const eth_addr &ea) +{ + *data = *ea.data; +} + +EthAddr::EthAddr(const std::string &addr) +{ + parse(addr); +} + +const EthAddr & +EthAddr::operator=(const eth_addr &ea) +{ + *data = *ea.data; + return *this; +} + +const EthAddr & +EthAddr::operator=(const std::string &addr) +{ + parse(addr); + return *this; +} + +void +EthAddr::parse(const std::string &addr) +{ + // the hack below is to make sure that ETH_ADDR_LEN is 6 otherwise + // the sscanf function won't work. + int bytes[ETH_ADDR_LEN == 6 ? ETH_ADDR_LEN : -1]; + if (sscanf(addr.c_str(), "%x:%x:%x:%x:%x:%x", &bytes[0], &bytes[1], + &bytes[2], &bytes[3], &bytes[4], &bytes[5]) != ETH_ADDR_LEN) { + memset(data, 0xff, ETH_ADDR_LEN); + return; + } + + for (int i = 0; i < ETH_ADDR_LEN; ++i) { + if (bytes[i] & ~0xff) { + memset(data, 0xff, ETH_ADDR_LEN); + return; + } + + data[i] = bytes[i]; + } +} + string -eaddr_string(const uint8_t a[6]) +EthAddr::string() const { stringstream stream; + stream << *this; + return stream.str(); +} + +bool +operator==(const EthAddr &left, const EthAddr &right) +{ + return memcmp(left.bytes(), right.bytes(), ETH_ADDR_LEN); +} + +ostream & +operator<<(ostream &stream, const EthAddr &ea) +{ + const uint8_t *a = ea.addr(); ccprintf(stream, "%x:%x:%x:%x:%x:%x", a[0], a[1], a[2], a[3], a[4], a[5]); + return stream; +} - return stream.str(); +uint16_t +cksum(const IpPtr &ptr) +{ + int sum = ip_cksum_add(ptr->bytes(), ptr->hlen(), 0); + return ip_cksum_carry(sum); } uint16_t -IpHdr::ip_cksum() const +__tu_cksum(const IpPtr &ip) { - int sum = ip_cksum_add(this, hlen(), 0); - sum = ip_cksum_carry(sum); - return sum; + int tcplen = ip->len() - ip->hlen(); + int sum = ip_cksum_add(ip->payload(), tcplen, 0); + sum = ip_cksum_add(&ip->ip_src, 8, sum); // source and destination + sum += htons(ip->ip_p + tcplen); + return ip_cksum_carry(sum); } uint16_t -IpHdr::tu_cksum() const +cksum(const TcpPtr &tcp) +{ return __tu_cksum(IpPtr(tcp.packet())); } + +uint16_t +cksum(const UdpPtr &udp) +{ return __tu_cksum(IpPtr(udp.packet())); } + +bool +IpHdr::options(vector<const IpOpt *> &vec) const { - int sum = ip_cksum_add(payload(), len() - hlen(), 0); - sum = ip_cksum_add(&ip_src, 8, sum); // source and destination - sum += htons(ip_p + len() - hlen()); - sum = ip_cksum_carry(sum); - return sum; + vec.clear(); + + const uint8_t *data = bytes() + sizeof(struct ip_hdr); + int all = hlen() - sizeof(struct ip_hdr); + while (all > 0) { + const IpOpt *opt = (const IpOpt *)data; + int len = opt->len(); + if (all < len) + return false; + + vec.push_back(opt); + all -= len; + data += len; + } + + return true; } + +bool +TcpHdr::options(vector<const TcpOpt *> &vec) const +{ + vec.clear(); + + const uint8_t *data = bytes() + sizeof(struct tcp_hdr); + int all = off() - sizeof(struct tcp_hdr); + while (all > 0) { + const TcpOpt *opt = (const TcpOpt *)data; + int len = opt->len(); + if (all < len) + return false; + + vec.push_back(opt); + all -= len; + data += len; + } + + return true; +} + +bool +TcpOpt::sack(vector<SackRange> &vec) const +{ + vec.clear(); + + const uint8_t *data = bytes() + sizeof(struct tcp_hdr); + int all = len() - offsetof(tcp_opt, opt_data.sack); + while (all > 0) { + const uint16_t *sack = (const uint16_t *)data; + int len = sizeof(uint16_t) * 2; + if (all < len) { + vec.clear(); + return false; + } + + vec.push_back(RangeIn(ntohs(sack[0]), ntohs(sack[1]))); + all -= len; + data += len; + } + + return false; +} + +/* namespace Net */ } diff --git a/base/inet.hh b/base/inet.hh index 8a49790a7..7ea4de6bb 100644 --- a/base/inet.hh +++ b/base/inet.hh @@ -29,10 +29,16 @@ #ifndef __BASE_INET_HH__ #define __BASE_INET_HH__ +#include <iosfwd> #include <string> +#include <utility> +#include <vector> -#include "dnet/os.h" +#include "base/range.hh" +#include "dev/etherpkt.hh" +#include "sim/host.hh" +#include "dnet/os.h" #include "dnet/eth.h" #include "dnet/ip.h" #include "dnet/ip6.h" @@ -41,45 +47,90 @@ #include "dnet/icmp.h" #include "dnet/tcp.h" #include "dnet/udp.h" - #include "dnet/intf.h" #include "dnet/route.h" #include "dnet/fw.h" - #include "dnet/blob.h" #include "dnet/rand.h" -#include "sim/host.hh" +namespace Net { -std::string eaddr_string(const uint8_t a[6]); +/* + * Ethernet Stuff + */ +struct EthAddr : protected eth_addr +{ + protected: + void parse(const std::string &addr); -struct EthHdr; -struct IpHdr; -struct TcpHdr; -struct UdpHdr; + public: + EthAddr(); + EthAddr(const uint8_t ea[ETH_ADDR_LEN]); + EthAddr(const eth_addr &ea); + EthAddr(const std::string &addr); + const EthAddr &operator=(const eth_addr &ea); + const EthAddr &operator=(const std::string &addr); -struct EthHdr : protected eth_hdr -{ - uint16_t type() const { return ntohs(eth_type); } + int size() const { return sizeof(eth_addr); } - const IpHdr *ip() const - { return type() == ETH_TYPE_IP ? (const IpHdr *)payload() : 0; } + const uint8_t *bytes() const { return &data[0]; } + uint8_t *bytes() { return &data[0]; } - IpHdr *ip() - { return type() == ETH_TYPE_IP ? (IpHdr *)payload() : 0; } + const uint8_t *addr() const { return &data[0]; } + bool unicast() const { return data[0] == 0x00; } + bool multicast() const { return data[0] == 0x01; } + bool broadcast() const { return data[0] == 0xff; } + std::string string() const; +}; + +std::ostream &operator<<(std::ostream &stream, const EthAddr &ea); +bool operator==(const EthAddr &left, const EthAddr &right); + +struct EthHdr : public eth_hdr +{ + uint16_t type() const { return ntohs(eth_type); } + const EthAddr &src() const { return *(EthAddr *)ð_src; } + const EthAddr &dst() const { return *(EthAddr *)ð_dst; } - bool unicast() { return eth_dst.data[0] == 0x00; } - bool multicast() { return eth_dst.data[0] == 0x01; } - bool broadcast() { return eth_dst.data[0] == 0xff; } + int size() const { return sizeof(eth_hdr); } - int size() const { return sizeof(EthHdr); } const uint8_t *bytes() const { return (const uint8_t *)this; } const uint8_t *payload() const { return bytes() + size(); } uint8_t *bytes() { return (uint8_t *)this; } uint8_t *payload() { return bytes() + size(); } }; -struct IpHdr : protected ip_hdr +class EthPtr +{ + protected: + friend class IpPtr; + PacketPtr p; + + public: + EthPtr() {} + EthPtr(const PacketPtr &ptr) : p(ptr) { } + + EthHdr *operator->() { return (EthHdr *)p->data; } + EthHdr &operator*() { return *(EthHdr *)p->data; } + operator EthHdr *() { return (EthHdr *)p->data; } + + const EthHdr *operator->() const { return (const EthHdr *)p->data; } + const EthHdr &operator*() const { return *(const EthHdr *)p->data; } + operator const EthHdr *() const { return (const EthHdr *)p->data; } + + const EthPtr &operator=(const PacketPtr &ptr) { p = ptr; return *this; } + + const PacketPtr packet() const { return p; } + PacketPtr packet() { return p; } + bool operator!() const { return !p; } + operator bool() const { return p; } +}; + +/* + * IP Stuff + */ +struct IpOpt; +struct IpHdr : public ip_hdr { uint8_t version() const { return ip_v; } uint8_t hlen() const { return ip_hl * 4; } @@ -96,19 +147,7 @@ struct IpHdr : protected ip_hdr void sum(uint16_t sum) { ip_sum = sum; } - uint16_t ip_cksum() const; - uint16_t tu_cksum() const; - - const TcpHdr *tcp() const - { return proto() == IP_PROTO_TCP ? (const TcpHdr *)payload() : 0; } - const UdpHdr *udp() const - { return proto() == IP_PROTO_UDP ? (const UdpHdr *)payload() : 0; } - - TcpHdr *tcp() - { return proto() == IP_PROTO_TCP ? (TcpHdr *)payload() : 0; } - UdpHdr *udp() - { return proto() == IP_PROTO_UDP ? (UdpHdr *)payload() : 0; } - + bool options(std::vector<const IpOpt *> &vec) const; int size() const { return hlen(); } const uint8_t *bytes() const { return (const uint8_t *)this; } @@ -117,7 +156,84 @@ struct IpHdr : protected ip_hdr uint8_t *payload() { return bytes() + size(); } }; -struct TcpHdr : protected tcp_hdr +class IpPtr +{ + protected: + friend class TcpPtr; + friend class UdpPtr; + PacketPtr p; + + const IpHdr *h() const + { return (const IpHdr *)(p->data + sizeof(eth_hdr)); } + IpHdr *h() { return (IpHdr *)(p->data + sizeof(eth_hdr)); } + + void set(const PacketPtr &ptr) + { + EthHdr *eth = (EthHdr *)ptr->data; + if (eth->type() == ETH_TYPE_IP) + p = ptr; + else + p = 0; + } + + public: + IpPtr() {} + IpPtr(const PacketPtr &ptr) { set(ptr); } + IpPtr(const EthPtr &ptr) { set(ptr.p); } + IpPtr(const IpPtr &ptr) : p(ptr.p) { } + + IpHdr *operator->() { return h(); } + IpHdr &operator*() { return *h(); } + operator IpHdr *() { return h(); } + + const IpHdr *operator->() const { return h(); } + const IpHdr &operator*() const { return *h(); } + operator const IpHdr *() const { return h(); } + + const IpPtr &operator=(const PacketPtr &ptr) { set(ptr); return *this; } + const IpPtr &operator=(const EthPtr &ptr) { set(ptr.p); return *this; } + const IpPtr &operator=(const IpPtr &ptr) { p = ptr.p; return *this; } + + const PacketPtr packet() const { return p; } + PacketPtr packet() { return p; } + bool operator!() const { return !p; } + operator bool() const { return p; } + operator bool() { return p; } +}; + +uint16_t cksum(const IpPtr &ptr); + +struct IpOpt : public ip_opt +{ + uint8_t type() const { return opt_type; } + uint8_t typeNumber() const { return IP_OPT_NUMBER(opt_type); } + uint8_t typeClass() const { return IP_OPT_CLASS(opt_type); } + uint8_t typeCopied() const { return IP_OPT_COPIED(opt_type); } + uint8_t len() const { return IP_OPT_TYPEONLY(type()) ? 1 : opt_len; } + + bool isNumber(int num) const { return typeNumber() == IP_OPT_NUMBER(num); } + bool isClass(int cls) const { return typeClass() == IP_OPT_CLASS(cls); } + bool isCopied(int cpy) const { return typeCopied() == IP_OPT_COPIED(cpy); } + + const uint8_t *data() const { return opt_data.data8; } + void sec(ip_opt_data_sec &sec) const; + void lsrr(ip_opt_data_rr &rr) const; + void ssrr(ip_opt_data_rr &rr) const; + void ts(ip_opt_data_ts &ts) const; + uint16_t satid() const { return ntohs(opt_data.satid); } + uint16_t mtup() const { return ntohs(opt_data.mtu); } + uint16_t mtur() const { return ntohs(opt_data.mtu); } + void tr(ip_opt_data_tr &tr) const; + const uint32_t *addext() const { return &opt_data.addext[0]; } + uint16_t rtralt() const { return ntohs(opt_data.rtralt); } + void sdb(std::vector<uint32_t> &vec) const; +}; + +/* + * TCP Stuff + */ +struct TcpOpt; +struct TcpHdr : public tcp_hdr { uint16_t sport() const { return ntohs(th_sport); } uint16_t dport() const { return ntohs(th_dport); } @@ -131,6 +247,8 @@ struct TcpHdr : protected tcp_hdr void sum(uint16_t sum) { th_sum = sum; } + bool options(std::vector<const TcpOpt *> &vec) const; + int size() const { return off(); } const uint8_t *bytes() const { return (const uint8_t *)this; } const uint8_t *payload() const { return bytes() + size(); } @@ -138,7 +256,81 @@ struct TcpHdr : protected tcp_hdr uint8_t *payload() { return bytes() + size(); } }; -struct UdpHdr : protected udp_hdr +class TcpPtr +{ + protected: + PacketPtr p; + int off; + + const TcpHdr *h() const { return (const TcpHdr *)(p->data + off); } + TcpHdr *h() { return (TcpHdr *)(p->data + off); } + + void set(const PacketPtr &ptr, int offset) { p = ptr; off = offset; } + void set(const IpPtr &ptr) + { + if (ptr->proto() == IP_PROTO_TCP) + set(ptr.p, sizeof(eth_hdr) + ptr->hlen()); + else + set(0, 0); + } + + public: + TcpPtr() {} + TcpPtr(const IpPtr &ptr) { set(ptr); } + TcpPtr(const TcpPtr &ptr) : p(ptr.p), off(ptr.off) {} + + TcpHdr *operator->() { return h(); } + TcpHdr &operator*() { return *h(); } + operator TcpHdr *() { return h(); } + + const TcpHdr *operator->() const { return h(); } + const TcpHdr &operator*() const { return *h(); } + operator const TcpHdr *() const { return h(); } + + const TcpPtr &operator=(const IpPtr &i) { set(i); return *this; } + const TcpPtr &operator=(const TcpPtr &t) { set(t.p, t.off); return *this; } + + const PacketPtr packet() const { return p; } + PacketPtr packet() { return p; } + bool operator!() const { return !p; } + operator bool() const { return p; } + operator bool() { return p; } +}; + +uint16_t cksum(const TcpPtr &ptr); + +typedef Range<uint16_t> SackRange; + +struct TcpOpt : public tcp_opt +{ + uint8_t type() const { return opt_type; } + uint8_t len() const { return TCP_OPT_TYPEONLY(type()) ? 1 : opt_len; } + + bool isopt(int opt) const { return type() == opt; } + + const uint8_t *data() const { return opt_data.data8; } + + uint16_t mss() const { return ntohs(opt_data.mss); } + uint8_t wscale() const { return opt_data.wscale; } + bool sack(std::vector<SackRange> &vec) const; + uint32_t echo() const { return ntohl(opt_data.echo); } + uint32_t tsval() const { return ntohl(opt_data.timestamp[0]); } + uint32_t tsecr() const { return ntohl(opt_data.timestamp[1]); } + uint32_t cc() const { return ntohl(opt_data.cc); } + uint8_t cksum() const{ return opt_data.cksum; } + const uint8_t *md5() const { return opt_data.md5; } + + int size() const { return len(); } + const uint8_t *bytes() const { return (const uint8_t *)this; } + const uint8_t *payload() const { return bytes() + size(); } + uint8_t *bytes() { return (uint8_t *)this; } + uint8_t *payload() { return bytes() + size(); } +}; + +/* + * UDP Stuff + */ +struct UdpHdr : public udp_hdr { uint16_t sport() const { return ntohs(uh_sport); } uint16_t dport() const { return ntohs(uh_dport); } @@ -147,11 +339,56 @@ struct UdpHdr : protected udp_hdr void sum(uint16_t sum) { uh_sum = htons(sum); } - int size() const { return sizeof(UdpHdr); } + int size() const { return sizeof(udp_hdr); } const uint8_t *bytes() const { return (const uint8_t *)this; } const uint8_t *payload() const { return bytes() + size(); } uint8_t *bytes() { return (uint8_t *)this; } uint8_t *payload() { return bytes() + size(); } }; +class UdpPtr +{ + protected: + PacketPtr p; + int off; + + const UdpHdr *h() const { return (const UdpHdr *)(p->data + off); } + UdpHdr *h() { return (UdpHdr *)(p->data + off); } + + void set(const PacketPtr &ptr, int offset) { p = ptr; off = offset; } + void set(const IpPtr &ptr) + { + if (ptr->proto() == IP_PROTO_UDP) + set(ptr.p, sizeof(eth_hdr) + ptr->hlen()); + else + set(0, 0); + } + + public: + UdpPtr() {} + UdpPtr(const IpPtr &ptr) { set(ptr); } + UdpPtr(const UdpPtr &ptr) : p(ptr.p), off(ptr.off) {} + + UdpHdr *operator->() { return h(); } + UdpHdr &operator*() { return *h(); } + operator UdpHdr *() { return h(); } + + const UdpHdr *operator->() const { return h(); } + const UdpHdr &operator*() const { return *h(); } + operator const UdpHdr *() const { return h(); } + + const UdpPtr &operator=(const IpPtr &i) { set(i); return *this; } + const UdpPtr &operator=(const UdpPtr &t) { set(t.p, t.off); return *this; } + + const PacketPtr packet() const { return p; } + PacketPtr packet() { return p; } + bool operator!() const { return !p; } + operator bool() const { return p; } + operator bool() { return p; } +}; + +uint16_t cksum(const UdpPtr &ptr); + +/* namespace Net */ } + #endif // __BASE_INET_HH__ diff --git a/base/refcnt.hh b/base/refcnt.hh index 251dc905b..00ba8fa4a 100644 --- a/base/refcnt.hh +++ b/base/refcnt.hh @@ -51,15 +51,26 @@ class RefCountingPtr protected: T *data; - void copy(T *d) { + void copy(T *d) + { data = d; if (data) data->incref(); } - void del() { + void del() + { if (data) data->decref(); } + void set(T *d) + { + if (data == d) + return; + + del(); + copy(d); + } + public: RefCountingPtr() : data(NULL) {} @@ -75,21 +86,9 @@ class RefCountingPtr const T &operator*() const { return *data; } const T *get() const { return data; } - RefCountingPtr &operator=(T *p) { - if (data != p) { - del(); - copy(p); - } - return *this; - } - - RefCountingPtr &operator=(const RefCountingPtr &r) { - if (data != r.data) { - del(); - copy(r.data); - } - return *this; - } + RefCountingPtr &operator=(T *p) { set(p); return *this; } + RefCountingPtr &operator=(const RefCountingPtr &r) + { return operator=(r.data); } bool operator!() const { return data == 0; } operator bool() const { return data != 0; } |