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 "net/esi.h"
7 :
8 : #include "base/parse_object.h"
9 : #include "base/util.h"
10 : #include "base/string_util.h"
11 : #include "base/address.h"
12 :
13 : using namespace std;
14 :
15 : static const uint8_t max_esi_bytes[] = {
16 : 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
17 : };
18 :
19 : const EthernetSegmentId EthernetSegmentId::kZeroEsi;
20 : const EthernetSegmentId EthernetSegmentId::kMaxEsi(max_esi_bytes);
21 :
22 565381 : EthernetSegmentId::EthernetSegmentId() {
23 565381 : memset(data_, 0, kSize);
24 565381 : }
25 :
26 26882 : EthernetSegmentId::EthernetSegmentId(const uint8_t *data) {
27 26882 : memcpy(data_, data, kSize);
28 26882 : }
29 :
30 6406 : EthernetSegmentId EthernetSegmentId::FromString(const std::string &str,
31 : boost::system::error_code *errorp) {
32 6406 : if (str == "zero_esi")
33 1 : return EthernetSegmentId::kZeroEsi;
34 6405 : if (str == "max_esi")
35 1 : return EthernetSegmentId::kMaxEsi;
36 :
37 6404 : size_t num_colons = count(str.begin(), str.end(), ':');
38 6404 : if (num_colons != 1 && num_colons != 9) {
39 4 : if (errorp != NULL)
40 4 : *errorp = make_error_code(boost::system::errc::invalid_argument);
41 4 : return EthernetSegmentId::kMaxEsi;
42 : }
43 :
44 : uint8_t data[kSize];
45 6400 : memset(data, 0, kSize);
46 :
47 : // AS based or IP based.
48 6400 : if (num_colons == 1) {
49 9 : size_t pos = str.find(':');
50 9 : assert(pos != string::npos);
51 9 : string asn_or_ip(str.substr(0, pos));
52 :
53 9 : size_t num_dots = count(asn_or_ip.begin(), asn_or_ip.end(), '.');
54 9 : if (num_dots != 0 && num_dots != 3) {
55 1 : if (errorp != NULL)
56 1 : *errorp = make_error_code(boost::system::errc::invalid_argument);
57 1 : return EthernetSegmentId::kMaxEsi;
58 : }
59 :
60 : // AS based.
61 8 : if (num_dots == 0) {
62 : uint32_t asn;
63 4 : bool ret = stringToInteger(asn_or_ip, asn);
64 4 : if (!ret) {
65 1 : if (errorp != NULL) {
66 1 : *errorp = make_error_code(boost::system::errc::invalid_argument);
67 1 : return EthernetSegmentId::kMaxEsi;
68 : }
69 : }
70 :
71 3 : data[0] = AS_BASED;
72 3 : put_value(&data[1], 4, asn);
73 : }
74 :
75 : // IP based.
76 7 : if (num_dots == 3) {
77 4 : boost::system::error_code ec;
78 4 : Ip4Address addr = Ip4Address::from_string(asn_or_ip, ec);
79 4 : if (ec.value() != 0) {
80 1 : if (errorp != NULL) {
81 1 : *errorp = make_error_code(boost::system::errc::invalid_argument);
82 1 : return EthernetSegmentId::kMaxEsi;
83 : }
84 : }
85 :
86 3 : data[0] = IP_BASED;
87 3 : const Ip4Address::bytes_type &bytes = addr.to_bytes();
88 3 : copy(bytes.begin(), bytes.begin() + 4, &data[1]);
89 : }
90 :
91 : // Parse discriminator - common for AS based and IP based.
92 6 : string disc_str(str, pos + 1);
93 : uint32_t disc;
94 6 : bool ret = stringToInteger(disc_str, disc);
95 6 : if (!ret) {
96 2 : if (errorp != NULL) {
97 2 : *errorp = make_error_code(boost::system::errc::invalid_argument);
98 2 : return EthernetSegmentId::kMaxEsi;
99 : }
100 : }
101 4 : put_value(&data[5], 4, disc);
102 11 : }
103 :
104 : // All other formats - raw colon separated bytes.
105 6395 : if (num_colons == 9) {
106 : char extra;
107 6391 : int ret = sscanf(str.c_str(),
108 : "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx%c",
109 : &data[0], &data[1], &data[2], &data[3], &data[4],
110 : &data[5], &data[6], &data[7], &data[8], &data[9], &extra);
111 6391 : if (ret != kSize || strchr(str.c_str(), 'x') || strchr(str.c_str(), 'X')) {
112 3 : if (errorp != NULL)
113 3 : *errorp = make_error_code(boost::system::errc::invalid_argument);
114 3 : return EthernetSegmentId::kMaxEsi;
115 : }
116 : }
117 :
118 6392 : return EthernetSegmentId(data);
119 : }
120 :
121 3225 : string EthernetSegmentId::ToString() const {
122 3225 : if (CompareTo(kZeroEsi) == 0)
123 2 : return "zero_esi";
124 3223 : if (CompareTo(kMaxEsi) == 0)
125 2 : return "max_esi";
126 :
127 3221 : switch (Type()) {
128 4 : case AS_BASED: {
129 4 : uint32_t asn = get_value(data_ + 1, 4);
130 4 : uint32_t value = get_value(data_ + 5, 4);
131 8 : return integerToString(asn) + ":" + integerToString(value);
132 : break;
133 : }
134 4 : case IP_BASED: {
135 4 : Ip4Address addr(get_value(data_ + 1, 4));
136 4 : uint32_t value = get_value(data_ + 5, 4);
137 8 : return addr.to_string() + ":" + integerToString(value);
138 : break;
139 : }
140 3213 : case MAC_BASED:
141 : case STP_BASED:
142 : case LACP_BASED:
143 : case CONFIGURED:
144 : default: {
145 : char temp[64];
146 3213 : snprintf(temp, sizeof(temp),
147 : "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
148 3213 : data_[0], data_[1], data_[2], data_[3], data_[4],
149 3213 : data_[5], data_[6], data_[7], data_[8], data_[9]);
150 3213 : return temp;
151 : }
152 : }
153 :
154 : return "bad_esi";
155 : }
156 :
157 29113488 : int EthernetSegmentId::CompareTo(const EthernetSegmentId &rhs) const {
158 29113488 : return memcmp(data_, rhs.data_, kSize);
159 : }
|