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