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 <stdint.h>
7 : #include "base/os.h"
8 : #include "base/address_util.h"
9 : #include "vr_defs.h"
10 : #include "cmn/agent_cmn.h"
11 : #include "oper/route_common.h"
12 : #include "pkt/pkt_init.h"
13 : #include "services/dhcpv6_proto.h"
14 : #include "services/services_types.h"
15 : #include "services/services_init.h"
16 : #include "services/dns_proto.h"
17 : #include "services/services_sandesh.h"
18 : #include "bind/bind_util.h"
19 : #include "bind/xmpp_dns_agent.h"
20 :
21 : #include <boost/assign/list_of.hpp>
22 : #include <boost/scoped_array.hpp>
23 : using namespace boost::assign;
24 :
25 : // since the DHCPv4 and DHCPv6 option codes mean different things
26 : // and since we get only one set of DHCP options from the config or
27 : // from Neutron, it is assumed that if the option code is a number,
28 : // it represents DHCPv4 code and the code string for DHCPv6 and
29 : // DHCPv4 do not overlap.
30 : Dhcpv6NameCodeMap g_dhcpv6_namecode_map =
31 : map_list_of<std::string, uint32_t>
32 : ("v6-client-id", DHCPV6_OPTION_CLIENTID)
33 : ("v6-server-id", DHCPV6_OPTION_SERVERID)
34 : ("v6-ia-na", DHCPV6_OPTION_IA_NA)
35 : ("v6-ia-ta", DHCPV6_OPTION_IA_TA)
36 : ("v6-ia-addr", DHCPV6_OPTION_IAADDR)
37 : ("v6-oro", DHCPV6_OPTION_ORO)
38 : ("v6-preference", DHCPV6_OPTION_PREFERENCE)
39 : ("v6-elapsed-time", DHCPV6_OPTION_ELAPSED_TIME)
40 : ("v6-relay-msg", DHCPV6_OPTION_RELAY_MSG)
41 : ("v6-auth", DHCPV6_OPTION_AUTH)
42 : ("v6-unicast", DHCPV6_OPTION_UNICAST)
43 : ("v6-status-code", DHCPV6_OPTION_STATUS_CODE)
44 : ("v6-rapid-commit", DHCPV6_OPTION_RAPID_COMMIT)
45 : ("v6-user-class", DHCPV6_OPTION_USER_CLASS)
46 : ("v6-vendor-class", DHCPV6_OPTION_VENDOR_CLASS)
47 : ("v6-vendor-opts", DHCPV6_OPTION_VENDOR_OPTS)
48 : ("v6-interface-id", DHCPV6_OPTION_INTERFACE_ID)
49 : ("v6-reconf-msg", DHCPV6_OPTION_RECONF_MSG)
50 : ("v6-reconf-accept", DHCPV6_OPTION_RECONF_ACCEPT)
51 : ("v6-sip-server-names", DHCPV6_OPTION_SIP_SERVER_D)
52 : ("v6-sip-server-addresses", DHCPV6_OPTION_SIP_SERVER_A)
53 : ("v6-name-servers", DHCPV6_OPTION_DNS_SERVERS)
54 : ("v6-domain-search", DHCPV6_OPTION_DOMAIN_LIST)
55 : ("v6-ia-pd", DHCPV6_OPTION_IA_PD)
56 : ("v6-ia-prefix", DHCPV6_OPTION_IAPREFIX)
57 : ("v6-nis-servers", DHCPV6_OPTION_NIS_SERVERS)
58 : ("v6-nisp-servers", DHCPV6_OPTION_NISP_SERVERS)
59 : ("v6-nis-domain-name", DHCPV6_OPTION_NIS_DOMAIN_NAME)
60 : ("v6-nisp-domain-name", DHCPV6_OPTION_NISP_DOMAIN_NAME)
61 : ("v6-sntp-servers", DHCPV6_OPTION_SNTP_SERVERS)
62 : ("v6-info-refresh-time", DHCPV6_OPTION_INFORMATION_REFRESH_TIME)
63 : ("v6-bcms-server-d", DHCPV6_OPTION_BCMCS_SERVER_D)
64 : ("v6-bcms-server-a", DHCPV6_OPTION_BCMCS_SERVER_A)
65 : ("v6-geoconf-civic", DHCPV6_OPTION_GEOCONF_CIVIC)
66 : ("v6-remote-id", DHCPV6_OPTION_REMOTE_ID)
67 : ("v6-subscriber-id", DHCPV6_OPTION_SUBSCRIBER_ID)
68 : ("v6-client-fqdn", DHCPV6_OPTION_CLIENT_FQDN)
69 : ("v6-pana-agent", DHCPV6_OPTION_PANA_AGENT)
70 : ("v6-posiz-timezone", DHCPV6_OPTION_NEW_POSIX_TIMEZONE)
71 : ("v6-tzdc-timezone", DHCPV6_OPTION_NEW_TZDB_TIMEZONE)
72 : ("v6-ero", DHCPV6_OPTION_ERO)
73 : ("v6-lq-query", DHCPV6_OPTION_LQ_QUERY)
74 : ("v6-client-data", DHCPV6_OPTION_CLIENT_DATA)
75 : ("v6-clt-time", DHCPV6_OPTION_CLT_TIME)
76 : ("v6-lq-relay-data", DHCPV6_OPTION_LQ_RELAY_DATA)
77 : ("v6-lq-client-link", DHCPV6_OPTION_LQ_CLIENT_LINK)
78 : ("mip6-hnidf", DHCPV6_OPTION_MIP6_HNIDF)
79 : ("mip6-vdinf", DHCPV6_OPTION_MIP6_VDINF)
80 : ("v6-lost", DHCPV6_OPTION_V6_LOST)
81 : ("v6-capwap-ac", DHCPV6_OPTION_CAPWAP_AC_V6)
82 : ("v6-relay-id", DHCPV6_OPTION_RELAY_ID)
83 : ("v6-address-mos", DHCPV6_OPTION_IPv6_Address_MoS)
84 : ("v6-fqdn-mos", DHCPV6_OPTION_IPv6_FQDN_MoS)
85 : ("v6-ntp-server", DHCPV6_OPTION_NTP_SERVER)
86 : ("v6-access-domain", DHCPV6_OPTION_V6_ACCESS_DOMAIN)
87 : ("v6-sip-ua-cs-list", DHCPV6_OPTION_SIP_UA_CS_LIST)
88 : ("v6-bootfile-url", DHCPV6_OPT_BOOTFILE_URL)
89 : ("v6-bootfile-param", DHCPV6_OPT_BOOTFILE_PARAM)
90 : ("v6-client-arch-type", DHCPV6_OPTION_CLIENT_ARCH_TYPE)
91 : ("v6-nii", DHCPV6_OPTION_NII)
92 : ("v6-geolocation", DHCPV6_OPTION_GEOLOCATION)
93 : ("v6-aftr-name", DHCPV6_OPTION_AFTR_NAME)
94 : ("v6-erp-local-domain-name", DHCPV6_OPTION_ERP_LOCAL_DOMAIN_NAME)
95 : ("v6-rsoo", DHCPV6_OPTION_RSOO)
96 : ("v6-pd-exclude", DHCPV6_OPTION_PD_EXCLUDE)
97 : ("v6-vss", DHCPV6_OPTION_VSS)
98 : ("mip6-idinf", DHCPV6_OPTION_MIP6_IDINF)
99 : ("mip6-udinf", DHCPV6_OPTION_MIP6_UDINF)
100 : ("mip6-hnp", DHCPV6_OPTION_MIP6_HNP)
101 : ("mip6-haa", DHCPV6_OPTION_MIP6_HAA)
102 : ("mip6-haf", DHCPV6_OPTION_MIP6_HAF)
103 : ("v6-rdnss-selection", DHCPV6_OPTION_RDNSS_SELECTION)
104 : ("v6-krb-principal-name", DHCPV6_OPTION_KRB_PRINCIPAL_NAME)
105 : ("v6-krb-realm-name", DHCPV6_OPTION_KRB_REALM_NAME)
106 : ("v6-krb-default-realm-name", DHCPV6_OPTION_KRB_DEFAULT_REALM_NAME)
107 : ("v6-krb-kdc", DHCPV6_OPTION_KRB_KDC)
108 : ("v6-client-linklayer-addr", DHCPV6_OPTION_CLIENT_LINKLAYER_ADDR)
109 : ("v6-link-address", DHCPV6_OPTION_LINK_ADDRESS)
110 : ("v6-radius", DHCPV6_OPTION_RADIUS)
111 : ("v6-sol-max-rt", DHCPV6_OPTION_SOL_MAX_RT)
112 : ("v6-inf-max-rt", DHCPV6_OPTION_INF_MAX_RT)
113 : ("v6-addrsel", DHCPV6_OPTION_ADDRSEL)
114 : ("v6-addrsel-table", DHCPV6_OPTION_ADDRSEL_TABLE)
115 : ("v6-pcp-server", DHCPV6_OPTION_V6_PCP_SERVER)
116 : ("v6-dhcpv4-msg", DHCPV6_OPTION_DHCPV4_MSG)
117 : ("v6-dhcpv4-o-dhcpv6-server", DHCPV6_OPTION_DHCP4_O_DHCP6_SERVER)
118 : ("v6-s46-rule", DHCPV6_OPTION_S46_RULE)
119 : ("v6-s46-br", DHCPV6_OPTION_S46_BR)
120 : ("v6-s46-dmr", DHCPV6_OPTION_S46_DMR)
121 : ("v6-s46-v4v6bind", DHCPV6_OPTION_S46_V4V6BIND)
122 : ("v6-s46-portparams", DHCPV6_OPTION_S46_PORTPARAMS)
123 : ("v6-s46-cont-mape", DHCPV6_OPTION_S46_CONT_MAPE)
124 : ("v6-s46-cont-mapt", DHCPV6_OPTION_S46_CONT_MAPT)
125 : ("v6-s46-cont-lw", DHCPV6_OPTION_S46_CONT_LW)
126 : ("v6-address-andsf", DHCPV6_OPTION_IPv6_ADDRESS_ANDSF);
127 :
128 : Dhcpv6CategoryMap g_dhcpv6_category_map =
129 : map_list_of<uint32_t, Dhcpv6Handler::DhcpOptionCategory>
130 : // the following are sent from Agent
131 : // (DHCPV6_OPTION_CLIENTID, Dhcpv6Handler::ByteArray)
132 : // (DHCPV6_OPTION_SERVERID, Dhcpv6Handler::ByteArray)
133 : // (DHCPV6_OPTION_IA_NA, Dhcpv6Handler::ByteArray)
134 : // (DHCPV6_OPTION_IA_TA, Dhcpv6Handler::ByteArray)
135 : // (DHCPV6_OPTION_IAADDR, Dhcpv6Handler::ByteArray)
136 : // (DHCPV6_OPTION_ORO, Dhcpv6Handler::ByteArray)
137 : (DHCPV6_OPTION_PREFERENCE, Dhcpv6Handler::Byte)
138 : // (DHCPV6_OPTION_ELAPSED_TIME, Dhcpv6Handler::Uint16bit)
139 : // (DHCPV6_OPTION_RELAY_MSG, Dhcpv6Handler::ByteArray)
140 : // (DHCPV6_OPTION_AUTH, Dhcpv6Handler::ByteArray)
141 : // (DHCPV6_OPTION_UNICAST, Dhcpv6Handler::OneIPv6)
142 : // (DHCPV6_OPTION_STATUS_CODE, Dhcpv6Handler::ByteArray)
143 : (DHCPV6_OPTION_RAPID_COMMIT, Dhcpv6Handler::NoData)
144 : (DHCPV6_OPTION_USER_CLASS, Dhcpv6Handler::ByteArray)
145 : (DHCPV6_OPTION_VENDOR_CLASS, Dhcpv6Handler::ByteArray)
146 : (DHCPV6_OPTION_VENDOR_OPTS, Dhcpv6Handler::ByteArray)
147 : (DHCPV6_OPTION_INTERFACE_ID, Dhcpv6Handler::ByteArray)
148 : (DHCPV6_OPTION_RECONF_MSG, Dhcpv6Handler::Byte)
149 : (DHCPV6_OPTION_RECONF_ACCEPT, Dhcpv6Handler::NoData)
150 : (DHCPV6_OPTION_SIP_SERVER_D, Dhcpv6Handler::NameCompressionArray)
151 : (DHCPV6_OPTION_SIP_SERVER_A, Dhcpv6Handler::OneIPv6Plus)
152 : (DHCPV6_OPTION_DNS_SERVERS, Dhcpv6Handler::OneIPv6Plus)
153 : (DHCPV6_OPTION_DOMAIN_LIST, Dhcpv6Handler::NameCompressionArray)
154 : (DHCPV6_OPTION_IA_PD, Dhcpv6Handler::ByteArray)
155 : (DHCPV6_OPTION_IAPREFIX, Dhcpv6Handler::ByteArray)
156 : (DHCPV6_OPTION_NIS_SERVERS, Dhcpv6Handler::OneIPv6Plus)
157 : (DHCPV6_OPTION_NISP_SERVERS, Dhcpv6Handler::OneIPv6Plus)
158 : (DHCPV6_OPTION_NIS_DOMAIN_NAME, Dhcpv6Handler::NameCompression)
159 : (DHCPV6_OPTION_NISP_DOMAIN_NAME, Dhcpv6Handler::NameCompression)
160 : (DHCPV6_OPTION_SNTP_SERVERS, Dhcpv6Handler::OneIPv6Plus)
161 : (DHCPV6_OPTION_INFORMATION_REFRESH_TIME, Dhcpv6Handler::Uint32bit)
162 : (DHCPV6_OPTION_BCMCS_SERVER_D, Dhcpv6Handler::NameCompressionArray)
163 : (DHCPV6_OPTION_BCMCS_SERVER_A, Dhcpv6Handler::OneIPv6Plus)
164 : (DHCPV6_OPTION_GEOCONF_CIVIC, Dhcpv6Handler::ByteArray)
165 : (DHCPV6_OPTION_REMOTE_ID, Dhcpv6Handler::ByteArray)
166 : (DHCPV6_OPTION_SUBSCRIBER_ID, Dhcpv6Handler::ByteArray)
167 : (DHCPV6_OPTION_CLIENT_FQDN, Dhcpv6Handler::ByteNameCompression)
168 : (DHCPV6_OPTION_PANA_AGENT, Dhcpv6Handler::OneIPv6Plus)
169 : (DHCPV6_OPTION_NEW_POSIX_TIMEZONE, Dhcpv6Handler::String)
170 : (DHCPV6_OPTION_NEW_TZDB_TIMEZONE, Dhcpv6Handler::String)
171 : (DHCPV6_OPTION_ERO, Dhcpv6Handler::Uint16bitArray)
172 : (DHCPV6_OPTION_LQ_QUERY, Dhcpv6Handler::ByteArray)
173 : (DHCPV6_OPTION_CLIENT_DATA, Dhcpv6Handler::ByteArray)
174 : (DHCPV6_OPTION_CLT_TIME, Dhcpv6Handler::Uint32bit)
175 : (DHCPV6_OPTION_LQ_RELAY_DATA, Dhcpv6Handler::ByteArray)
176 : (DHCPV6_OPTION_LQ_CLIENT_LINK, Dhcpv6Handler::OneIPv6Plus)
177 : (DHCPV6_OPTION_MIP6_HNIDF, Dhcpv6Handler::NameCompression)
178 : (DHCPV6_OPTION_MIP6_VDINF, Dhcpv6Handler::ByteArray)
179 : (DHCPV6_OPTION_V6_LOST, Dhcpv6Handler::NameCompression)
180 : (DHCPV6_OPTION_CAPWAP_AC_V6, Dhcpv6Handler::OneIPv6Plus)
181 : (DHCPV6_OPTION_RELAY_ID, Dhcpv6Handler::ByteArray)
182 : (DHCPV6_OPTION_IPv6_Address_MoS, Dhcpv6Handler::ByteArray)
183 : (DHCPV6_OPTION_IPv6_FQDN_MoS, Dhcpv6Handler::ByteArray)
184 : (DHCPV6_OPTION_NTP_SERVER, Dhcpv6Handler::ByteArray)
185 : (DHCPV6_OPTION_V6_ACCESS_DOMAIN, Dhcpv6Handler::NameCompression)
186 : (DHCPV6_OPTION_SIP_UA_CS_LIST, Dhcpv6Handler::NameCompressionArray)
187 : (DHCPV6_OPT_BOOTFILE_URL, Dhcpv6Handler::String)
188 : (DHCPV6_OPT_BOOTFILE_PARAM, Dhcpv6Handler::ByteArray)
189 : (DHCPV6_OPTION_CLIENT_ARCH_TYPE, Dhcpv6Handler::Uint16bitArray)
190 : (DHCPV6_OPTION_NII, Dhcpv6Handler::ByteArray)
191 : (DHCPV6_OPTION_GEOLOCATION, Dhcpv6Handler::ByteArray)
192 : (DHCPV6_OPTION_AFTR_NAME, Dhcpv6Handler::NameCompression)
193 : (DHCPV6_OPTION_ERP_LOCAL_DOMAIN_NAME, Dhcpv6Handler::NameCompression)
194 : (DHCPV6_OPTION_RSOO, Dhcpv6Handler::ByteArray)
195 : (DHCPV6_OPTION_PD_EXCLUDE, Dhcpv6Handler::ByteArray)
196 : (DHCPV6_OPTION_VSS, Dhcpv6Handler::ByteArray)
197 : (DHCPV6_OPTION_MIP6_IDINF, Dhcpv6Handler::ByteArray)
198 : (DHCPV6_OPTION_MIP6_UDINF, Dhcpv6Handler::ByteArray)
199 : (DHCPV6_OPTION_MIP6_HNP, Dhcpv6Handler::ByteArray)
200 : (DHCPV6_OPTION_MIP6_HAA, Dhcpv6Handler::OneIPv6)
201 : (DHCPV6_OPTION_MIP6_HAF, Dhcpv6Handler::NameCompression)
202 : (DHCPV6_OPTION_RDNSS_SELECTION, Dhcpv6Handler::ByteArray)
203 : (DHCPV6_OPTION_KRB_PRINCIPAL_NAME, Dhcpv6Handler::ByteArray)
204 : (DHCPV6_OPTION_KRB_REALM_NAME, Dhcpv6Handler::ByteArray)
205 : (DHCPV6_OPTION_KRB_DEFAULT_REALM_NAME, Dhcpv6Handler::ByteArray)
206 : (DHCPV6_OPTION_KRB_KDC, Dhcpv6Handler::ByteArray)
207 : (DHCPV6_OPTION_CLIENT_LINKLAYER_ADDR, Dhcpv6Handler::ByteArray)
208 : (DHCPV6_OPTION_LINK_ADDRESS, Dhcpv6Handler::OneIPv6)
209 : (DHCPV6_OPTION_RADIUS, Dhcpv6Handler::ByteArray)
210 : (DHCPV6_OPTION_SOL_MAX_RT, Dhcpv6Handler::Uint32bit)
211 : (DHCPV6_OPTION_INF_MAX_RT, Dhcpv6Handler::Uint32bit)
212 : (DHCPV6_OPTION_ADDRSEL, Dhcpv6Handler::ByteArray)
213 : (DHCPV6_OPTION_ADDRSEL_TABLE, Dhcpv6Handler::ByteArray)
214 : (DHCPV6_OPTION_V6_PCP_SERVER, Dhcpv6Handler::OneIPv6Plus)
215 : (DHCPV6_OPTION_DHCPV4_MSG, Dhcpv6Handler::ByteArray)
216 : (DHCPV6_OPTION_DHCP4_O_DHCP6_SERVER, Dhcpv6Handler::ByteArray)
217 : (DHCPV6_OPTION_S46_RULE, Dhcpv6Handler::ByteArray)
218 : (DHCPV6_OPTION_S46_BR, Dhcpv6Handler::OneIPv6)
219 : (DHCPV6_OPTION_S46_DMR, Dhcpv6Handler::ByteArray)
220 : (DHCPV6_OPTION_S46_V4V6BIND, Dhcpv6Handler::ByteArray)
221 : (DHCPV6_OPTION_S46_PORTPARAMS, Dhcpv6Handler::ByteArray)
222 : (DHCPV6_OPTION_S46_CONT_MAPE, Dhcpv6Handler::ByteArray)
223 : (DHCPV6_OPTION_S46_CONT_MAPT, Dhcpv6Handler::ByteArray)
224 : (DHCPV6_OPTION_S46_CONT_LW, Dhcpv6Handler::ByteArray)
225 : (DHCPV6_OPTION_IPv6_ADDRESS_ANDSF, Dhcpv6Handler::OneIPv6Plus);
226 :
227 0 : Dhcpv6Handler::Dhcpv6Handler(Agent *agent, boost::shared_ptr<PktInfo> info,
228 0 : boost::asio::io_context &io)
229 : : DhcpHandlerBase(agent, info, io),
230 0 : msg_type_(DHCPV6_UNKNOWN), out_msg_type_(DHCPV6_UNKNOWN),
231 0 : rapid_commit_(false), reconfig_accept_(false),
232 0 : client_duid_len_(0), server_duid_len_(0),
233 0 : client_duid_(NULL), server_duid_(NULL), is_ia_na_(true) {
234 0 : memset(xid_, 0, sizeof(xid_));
235 0 : option_.reset(new Dhcpv6OptionHandler(NULL));
236 0 : }
237 :
238 0 : Dhcpv6Handler::~Dhcpv6Handler() {
239 0 : }
240 :
241 0 : bool Dhcpv6Handler::Run() {
242 0 : Dhcpv6Proto *dhcp_proto = agent()->dhcpv6_proto();
243 : // options length = pkt length - size of headers
244 0 : int16_t options_len = pkt_info_->len -
245 0 : (pkt_info_->data - (uint8_t *)pkt_info_->pkt)
246 0 : - DHCPV6_FIXED_LEN;
247 0 : if (options_len < 0) {
248 0 : dhcp_proto->IncrStatsError();
249 0 : DHCPV6_TRACE(Error, "Improper DHCPv6 packet length; vrf = " <<
250 : pkt_info_->vrf << " ifindex = " << GetInterfaceIndex());
251 0 : return true;
252 : }
253 :
254 0 : dhcp_ = (Dhcpv6Hdr *) pkt_info_->data;
255 0 : option_->SetDhcpOptionPtr((uint8_t *)dhcp_ + DHCPV6_FIXED_LEN);
256 : // request_.UpdateData(dhcp_->xid, ntohs(dhcp_->flags), dhcp_->chaddr);
257 : Interface *itf =
258 0 : agent()->interface_table()->FindInterface(GetInterfaceIndex());
259 0 : if (itf == NULL) {
260 0 : dhcp_proto->IncrStatsError();
261 0 : DHCPV6_TRACE(Error, "Received DHCP packet on invalid interface : "
262 : << GetInterfaceIndex());
263 0 : return true;
264 : }
265 :
266 0 : if (itf->type() != Interface::VM_INTERFACE) {
267 0 : dhcp_proto->IncrStatsError();
268 0 : DHCPV6_TRACE(Error, "Received DHCP packet on non VM port interface : "
269 : << GetInterfaceIndex());
270 0 : return true;
271 : }
272 0 : vm_itf_ = static_cast<VmInterface *>(itf);
273 0 : if (!vm_itf_->dhcp_enable_v6_config()) {
274 0 : dhcp_proto->IncrStatsError();
275 0 : DHCPV6_TRACE(Error, "DHCP request on VM port with dhcp services disabled: "
276 : << GetInterfaceIndex());
277 0 : return true;
278 : }
279 :
280 0 : msg_type_ = dhcp_->type;
281 0 : memcpy(xid_, dhcp_->xid, 3);
282 0 : ReadOptions(options_len);
283 :
284 0 : switch (msg_type_) {
285 0 : case DHCPV6_SOLICIT:
286 0 : out_msg_type_ = DHCPV6_ADVERTISE;
287 0 : dhcp_proto->IncrStatsSolicit();
288 0 : DHCPV6_TRACE(Trace, "DHCP solicit received on interface : "
289 : << vm_itf_->name());
290 0 : break;
291 :
292 0 : case DHCPV6_REQUEST:
293 0 : out_msg_type_ = DHCPV6_REPLY;
294 0 : dhcp_proto->IncrStatsRequest();
295 0 : DHCPV6_TRACE(Trace, "DHCP request received on interface : "
296 : << vm_itf_->name());
297 0 : break;
298 :
299 : // TODO: following messages require special handling
300 0 : case DHCPV6_CONFIRM:
301 0 : out_msg_type_ = DHCPV6_REPLY;
302 0 : dhcp_proto->IncrStatsConfirm();
303 0 : DHCPV6_TRACE(Trace, "DHCP confirm received on interface : "
304 : << vm_itf_->name());
305 0 : break;
306 :
307 0 : case DHCPV6_RENEW:
308 0 : out_msg_type_ = DHCPV6_REPLY;
309 0 : dhcp_proto->IncrStatsRenew();
310 0 : DHCPV6_TRACE(Trace, "DHCP renew received on interface : "
311 : << vm_itf_->name());
312 0 : break;
313 :
314 0 : case DHCPV6_REBIND:
315 0 : out_msg_type_ = DHCPV6_REPLY;
316 0 : dhcp_proto->IncrStatsRebind();
317 0 : DHCPV6_TRACE(Trace, "DHCP bind received on interface : "
318 : << vm_itf_->name());
319 0 : break;
320 :
321 0 : case DHCPV6_RELEASE:
322 0 : out_msg_type_ = DHCPV6_REPLY;
323 0 : dhcp_proto->IncrStatsRelease();
324 0 : DHCPV6_TRACE(Trace, "DHCP release received on interface : "
325 : << vm_itf_->name());
326 0 : break;
327 :
328 0 : case DHCPV6_DECLINE:
329 0 : out_msg_type_ = DHCPV6_REPLY;
330 0 : dhcp_proto->IncrStatsDecline();
331 0 : DHCPV6_TRACE(Trace, "DHCP decline received on interface : "
332 : << vm_itf_->name());
333 0 : break;
334 :
335 0 : case DHCPV6_RECONFIGURE:
336 0 : dhcp_proto->IncrStatsReconfigure();
337 0 : DHCPV6_TRACE(Trace, "DHCP reconfigure received on interface : "
338 : << vm_itf_->name());
339 0 : break;
340 :
341 0 : case DHCPV6_INFORMATION_REQUEST:
342 0 : dhcp_proto->IncrStatsInformationRequest();
343 0 : DHCPV6_TRACE(Trace,
344 : "DHCP information request received on interface : "
345 : << vm_itf_->name());
346 0 : break;
347 :
348 0 : default:
349 0 : DHCPV6_TRACE(Trace, "DHCP message " << msg_type_ <<
350 : " received on interface : " << vm_itf_->name() <<
351 : "; ignoring");
352 0 : dhcp_proto->IncrStatsError();
353 0 : return true;
354 : }
355 :
356 0 : if (FindLeaseData()) {
357 0 : SendDhcpResponse();
358 0 : DHCPV6_TRACE(Trace, "DHCP response sent; message = " <<
359 : ServicesSandesh::Dhcpv6MsgType(out_msg_type_) <<
360 : "; ip = " << config_.ip_addr.to_string());
361 : }
362 :
363 0 : return true;
364 : }
365 :
366 : // read DHCP options in the incoming packet
367 0 : void Dhcpv6Handler::ReadOptions(int16_t opt_rem_len) {
368 0 : Dhcpv6Options *opt = reinterpret_cast<Dhcpv6Options *>(
369 0 : (uint8_t *)dhcp_ + DHCPV6_FIXED_LEN);
370 : // parse thru the option fields
371 0 : while (opt_rem_len > 0) {
372 0 : uint16_t option_code = ntohs(opt->code);
373 0 : uint16_t option_len = ntohs(opt->len);
374 0 : if (option_len > opt_rem_len) {
375 0 : DHCPV6_TRACE(Error, "DHCP option parsing error");
376 0 : break;
377 : }
378 0 : switch (option_code) {
379 0 : case DHCPV6_OPTION_CLIENTID:
380 0 : client_duid_len_ = option_len;
381 0 : client_duid_.reset(new uint8_t[client_duid_len_]);
382 0 : memcpy(client_duid_.get(), opt->data, client_duid_len_);
383 0 : break;
384 :
385 0 : case DHCPV6_OPTION_SERVERID:
386 0 : server_duid_len_ = option_len;
387 0 : server_duid_.reset(new uint8_t[server_duid_len_]);
388 0 : memcpy(server_duid_.get(), opt->data, server_duid_len_);
389 0 : break;
390 :
391 0 : case DHCPV6_OPTION_IA_NA:
392 0 : is_ia_na_ = true;
393 0 : ReadIA(opt->data, option_len, option_code);
394 0 : break;
395 :
396 0 : case DHCPV6_OPTION_IA_TA:
397 0 : is_ia_na_ = false;
398 0 : ReadIA(opt->data, option_len, option_code);
399 0 : break;
400 :
401 0 : case DHCPV6_OPTION_RAPID_COMMIT:
402 0 : rapid_commit_ = true;
403 0 : break;
404 :
405 0 : case DHCPV6_OPTION_RECONF_ACCEPT:
406 0 : reconfig_accept_ = true;
407 0 : break;
408 :
409 0 : case DHCPV6_OPTION_ORO: // list of requested options
410 : case DHCPV6_OPTION_PREFERENCE: // server preference, sent by server
411 : case DHCPV6_OPTION_ELAPSED_TIME: // time client has been trying
412 : case DHCPV6_OPTION_RELAY_MSG: // relay DHCP types are not handled
413 : case DHCPV6_OPTION_AUTH: // authentication
414 : case DHCPV6_OPTION_UNICAST: // server option, sent to get ucast msgs
415 : case DHCPV6_OPTION_USER_CLASS: // type of user
416 : case DHCPV6_OPTION_VENDOR_CLASS: // vendor
417 : case DHCPV6_OPTION_VENDOR_OPTS:
418 : case DHCPV6_OPTION_INTERFACE_ID: // used by relay agent
419 : case DHCPV6_OPTION_RECONF_MSG: // can only appear in reconfigure msg
420 : // ignore these options
421 0 : break;
422 :
423 0 : default:
424 0 : break;
425 : }
426 0 : opt_rem_len -= (4 + option_len);
427 0 : opt = (Dhcpv6Options *)((uint8_t *)opt + 4 + option_len);
428 : }
429 0 : }
430 :
431 0 : bool Dhcpv6Handler::ReadIA(uint8_t *ptr, uint16_t len, uint16_t code) {
432 0 : if (ia_na_.get() == NULL) {
433 0 : ia_na_.reset(new Dhcpv6IaData());
434 : }
435 :
436 0 : ia_na_->AddIa((Dhcpv6Ia *)ptr);
437 :
438 0 : int16_t iana_rem_len = len - sizeof(Dhcpv6Ia);
439 0 : Dhcpv6Options *iana_option = (Dhcpv6Options *)(ptr + sizeof(Dhcpv6Ia));
440 0 : while (iana_rem_len > 0) {
441 0 : uint16_t iana_option_code = ntohs(iana_option->code);
442 0 : uint16_t iana_option_len = ntohs(iana_option->len);
443 0 : switch (iana_option_code) {
444 0 : case DHCPV6_OPTION_IAADDR: {
445 0 : ia_na_->AddIaAddr((Dhcpv6IaAddr *)iana_option->data);
446 0 : break;
447 : }
448 :
449 0 : case DHCPV6_OPTION_STATUS_CODE: {
450 0 : uint16_t *s_ptr = reinterpret_cast<uint16_t *>
451 : (iana_option->data);
452 0 : uint16_t status = ntohs(*s_ptr);
453 0 : if (status != DHCPV6_SUCCESS) {
454 0 : std::string msg((const char *)iana_option->data + 2,
455 0 : iana_option_len - 2);
456 0 : DHCPV6_TRACE(Trace, "DHCP message with error status : " <<
457 : status << " error msg : " << msg <<
458 : "; received on interface : " <<
459 : vm_itf_->name() << "; ignoring");
460 0 : }
461 0 : return false;
462 : }
463 :
464 0 : default:
465 0 : break;
466 : }
467 0 : iana_rem_len -= (4 + iana_option_len);
468 0 : iana_option = (Dhcpv6Options *)((uint8_t *)iana_option + 4 + iana_option_len);
469 : }
470 :
471 0 : return true;
472 : }
473 :
474 0 : void Dhcpv6Handler::FillDhcpInfo(Ip6Address &addr, int plen,
475 : Ip6Address &gw, Ip6Address &dns) {
476 0 : config_.ip_addr = addr;
477 0 : config_.plen = plen;
478 0 : config_.gw_addr = gw;
479 0 : config_.dns_addr = dns;
480 0 : }
481 :
482 0 : bool Dhcpv6Handler::FindLeaseData() {
483 0 : Ip6Address ip = vm_itf_->primary_ip6_addr();
484 0 : FindDomainName(ip);
485 0 : if (vm_itf_->IsActive()) {
486 0 : if (vm_itf_->fabric_port()) {
487 : // TODO
488 0 : agent()->dhcpv6_proto()->IncrStatsError();
489 0 : DHCPV6_TRACE(Error, "DHCP fabric port request failed for : "
490 : << ip.to_string());
491 0 : return false;
492 : }
493 :
494 0 : const std::vector<VnIpam> &ipam = vm_itf_->vn()->GetVnIpam();
495 0 : for (uint32_t i = 0; i < ipam.size(); ++i) {
496 0 : if (!ipam[i].IsV6()) {
497 0 : continue;
498 : }
499 0 : if (IsIp6SubnetMember(ip, ipam[i].ip_prefix.to_v6(),
500 0 : ipam[i].plen)) {
501 0 : Ip6Address default_gw;
502 0 : if (ipam[i].default_gw.is_v6()) {
503 0 : default_gw = ipam[i].default_gw.to_v6();
504 : }
505 0 : Ip6Address service_address;
506 0 : if (ipam[i].dns_server.is_unspecified()) {
507 0 : service_address = default_gw;
508 : } else {
509 0 : if (ipam[i].dns_server.is_v6()) {
510 0 : service_address = ipam[i].dns_server.to_v6();
511 : }
512 : }
513 0 : FillDhcpInfo(ip, ipam[i].plen, default_gw, service_address);
514 0 : return true;
515 : }
516 : }
517 : }
518 :
519 : // We dont have the config yet; give a short lease
520 0 : config_.preferred_time = DHCPV6_SHORTLEASE_TIME;
521 0 : config_.valid_time = 2 * DHCPV6_SHORTLEASE_TIME;
522 : // Give address received from Nova
523 0 : Ip6Address empty;
524 0 : FillDhcpInfo(ip, 128, empty, empty);
525 0 : DHCPV6_TRACE(Trace, "DHCP giving short lease given for : " << ip.to_string()
526 : << "; IPv6 not active in Agent");
527 0 : return true;
528 : }
529 :
530 : // Add an IP address to the option
531 0 : uint16_t Dhcpv6Handler::AddIP(uint16_t opt_len, const std::string &input) {
532 0 : boost::system::error_code ec;
533 0 : Ip6Address ip = Ip6Address::from_string(input, ec);
534 0 : if (!ec.value()) {
535 0 : option_->AppendData(16, ip.to_bytes().data(), &opt_len);
536 : } else {
537 0 : DHCPV6_TRACE(Error, "Invalid DHCP option " << option_->GetCode() <<
538 : " for VM " << config_.ip_addr.to_string() <<
539 : "; has to be IP address");
540 : }
541 0 : return opt_len;
542 : }
543 :
544 : // Add domain name from IPAM to the option
545 0 : uint16_t Dhcpv6Handler::AddDomainNameOption(uint16_t opt_len) {
546 0 : if (ipam_type_.ipam_dns_method == "virtual-dns-server") {
547 0 : if (is_dns_enabled() && config_.domain_name_.size()) {
548 : // encode the domain name in the dns encoding format
549 0 : boost::scoped_array<uint8_t> domain_name(new uint8_t[config_.domain_name_.size() * 2 + 2]);
550 0 : uint16_t len = 0;
551 0 : BindUtil::AddName(domain_name.get(), config_.domain_name_, 0, 0, len);
552 0 : option_->WriteData(DHCPV6_OPTION_DOMAIN_LIST, len,
553 0 : domain_name.get(), &opt_len);
554 0 : }
555 : }
556 0 : return opt_len;
557 : }
558 :
559 0 : uint16_t Dhcpv6Handler::FillDhcpv6Hdr() {
560 0 : Dhcpv6Proto *dhcp_proto = agent()->dhcpv6_proto();
561 :
562 0 : dhcp_->type = out_msg_type_;
563 0 : memcpy(dhcp_->xid, xid_, 3);
564 :
565 0 : uint16_t opt_len = 0;
566 :
567 : // server duid
568 0 : option_->SetNextOptionPtr(opt_len);
569 0 : option_->WriteData(DHCPV6_OPTION_SERVERID, sizeof(Dhcpv6Proto::Duid),
570 0 : (void *)dhcp_proto->server_duid(), &opt_len);
571 :
572 : // client duid
573 0 : if (client_duid_len_) {
574 0 : option_->SetNextOptionPtr(opt_len);
575 0 : option_->WriteData(DHCPV6_OPTION_CLIENTID, client_duid_len_,
576 0 : (void *)client_duid_.get(), &opt_len);
577 : }
578 :
579 : // IA
580 0 : option_->SetNextOptionPtr(opt_len);
581 0 : WriteIaOption(opt_len);
582 :
583 : // Add dhcp options coming from Config
584 0 : opt_len = AddConfigDhcpOptions(opt_len, true);
585 :
586 : // GW doesnt come in DHCPV6, it should come via router advertisement
587 :
588 0 : if (!is_flag_set(DHCPV6_OPTION_DNS_SERVERS)) {
589 0 : uint16_t old_opt_len = opt_len;
590 0 : option_->SetNextOptionPtr(opt_len);
591 0 : option_->WriteData(DHCPV6_OPTION_DNS_SERVERS, 0, NULL, &opt_len);
592 0 : opt_len = AddDnsServers(opt_len);
593 : // if there was no DNS server, revert the option
594 0 : if (opt_len == old_opt_len + option_->GetFixedLen())
595 0 : opt_len = old_opt_len;
596 : }
597 :
598 0 : if (!is_flag_set(DHCPV6_OPTION_DOMAIN_LIST)) {
599 0 : option_->SetNextOptionPtr(opt_len);
600 0 : opt_len = AddDomainNameOption(opt_len);
601 : }
602 :
603 0 : return (DHCPV6_FIXED_LEN + opt_len);
604 : }
605 :
606 0 : void Dhcpv6Handler::IncrementByteInAddress(Ip6Address::bytes_type &bytes, uint8_t index) {
607 0 : if (index > 15) {
608 0 : return;
609 : }
610 0 : bytes[index]++;
611 0 : if (bytes[index] != 0) {
612 0 : return;
613 : } else {
614 0 : IncrementByteInAddress(bytes, index - 1);
615 : }
616 : }
617 :
618 0 : Ip6Address Dhcpv6Handler::GetNextV6Address(uint8_t addr[16]) {
619 : Ip6Address::bytes_type bytes;
620 0 : for (int i = 0; i < 16; i++) {
621 0 : bytes[i] = addr[i];
622 : }
623 0 : IncrementByteInAddress(bytes, 15);
624 0 : return Ip6Address(bytes);
625 : }
626 :
627 0 : void Dhcpv6Handler::WriteIaOption(uint16_t &optlen) {
628 0 : if (ia_na_.get() == NULL) {
629 0 : return;
630 : }
631 :
632 0 : uint32_t alloc_unit = 1;
633 : // for ia_ta, send only one address
634 0 : if (vm_itf_ && vm_itf_->vn() && is_ia_na_) {
635 0 : alloc_unit = vm_itf_->vn()->GetAllocUnitFromIpam(config_.ip_addr);
636 : }
637 0 : if (alloc_unit > 128) {
638 0 : DHCPV6_TRACE(Error, "Alloc-unit(" << alloc_unit << ") in Ipam is"
639 : " higher than supported value(128), using max supported"
640 : " value");
641 0 : alloc_unit = 128;
642 : }
643 0 : Dhcpv6IaAddr ia_addr(config_.ip_addr.to_v6().to_bytes().data(),
644 : config_.preferred_time,
645 0 : config_.valid_time);
646 :
647 0 : uint16_t ia_option = (is_ia_na_)? DHCPV6_OPTION_IA_NA : DHCPV6_OPTION_IA_TA;
648 0 : uint16_t ia_option_length = (is_ia_na_)? sizeof(Dhcpv6Ia) : 16;
649 0 : option_->WriteData(ia_option, ia_option_length, (void *)&ia_na_->ia, &optlen);
650 :
651 0 : for (uint32_t i = 0; i < alloc_unit; i++) {
652 0 : Dhcpv6Options *ia_addr_opt = GetNextOptionPtr(optlen);
653 0 : if (msg_type_ != DHCPV6_CONFIRM ||
654 0 : (msg_type_ == DHCPV6_CONFIRM && ia_na_->DelIaAddr(ia_addr))) {
655 0 : ia_addr_opt->WriteData(DHCPV6_OPTION_IAADDR, sizeof(Dhcpv6IaAddr),
656 : (void *)&ia_addr, &optlen);
657 0 : option_->AddLen(sizeof(Dhcpv6IaAddr) + 4);
658 : }
659 0 : Ip6Address next_ip = GetNextV6Address(ia_addr.address);
660 0 : memcpy(ia_addr.address, next_ip.to_bytes().data(), 16);
661 : }
662 :
663 : // in case of confirm, if there are any remaining addresses in ia_na_
664 : // add them with status as "NotOnLink".
665 0 : if (msg_type_ == DHCPV6_CONFIRM && !ia_na_->ia_addr.empty()) {
666 0 : for (std::vector<Dhcpv6IaAddr>::iterator it = ia_na_->ia_addr.begin();
667 0 : it != ia_na_->ia_addr.end(); ++it) {
668 0 : memcpy(ia_addr.address, it->address, 16);
669 0 : Dhcpv6Options *ia_addr_opt = GetNextOptionPtr(optlen);
670 0 : ia_addr_opt->WriteData(DHCPV6_OPTION_IAADDR, sizeof(Dhcpv6IaAddr),
671 : (void *)&ia_addr, &optlen);
672 0 : option_->AddLen(sizeof(Dhcpv6IaAddr) + 4);
673 0 : ia_addr_opt = GetNextOptionPtr(optlen);
674 0 : std::string message = "Some of the addresses are not on link";
675 0 : uint16_t status_code = htons(DHCPV6_NOT_ON_LINK);
676 0 : ia_addr_opt->WriteData(DHCPV6_OPTION_STATUS_CODE, 2,
677 : (void *)&status_code, &optlen);
678 0 : ia_addr_opt->AppendData(message.length(), message.c_str(), &optlen);
679 0 : option_->AddLen(message.length() + 6);
680 0 : }
681 : }
682 : }
683 :
684 0 : uint16_t Dhcpv6Handler::FillDhcpResponse(const MacAddress &dest_mac,
685 : Ip6Address src_ip, Ip6Address dest_ip) {
686 0 : pkt_info_->eth = (struct ether_header *)(pkt_info_->pkt);
687 0 : uint16_t eth_len = 0;
688 0 : eth_len = EthHdr((char *)pkt_info_->eth,
689 0 : pkt_info_->packet_buffer()->data_len(),
690 : GetInterfaceIndex(),
691 : agent()->vhost_interface()->mac(), dest_mac,
692 : ETHERTYPE_IPV6);
693 0 : pkt_info_->ip6 = (struct ip6_hdr *)((char *)pkt_info_->eth + eth_len);
694 0 : pkt_info_->transp.udp = (udphdr *)(pkt_info_->ip6 + 1);
695 0 : dhcp_ = (Dhcpv6Hdr *)(pkt_info_->transp.udp + 1);
696 0 : option_->SetDhcpOptionPtr((uint8_t *)dhcp_ + DHCPV6_FIXED_LEN);
697 :
698 0 : uint16_t len = FillDhcpv6Hdr();
699 0 : len += sizeof(udphdr);
700 0 : UdpHdr(len, src_ip.to_bytes().data(), DHCPV6_SERVER_PORT,
701 0 : dest_ip.to_bytes().data(), DHCPV6_CLIENT_PORT, IPPROTO_UDP);
702 0 : Ip6Hdr(pkt_info_->ip6, len, IPPROTO_UDP, 64, src_ip.to_bytes().data(),
703 0 : dest_ip.to_bytes().data());
704 0 : len += sizeof(ip6_hdr);
705 :
706 0 : pkt_info_->set_len(len + eth_len);
707 0 : return pkt_info_->packet_buffer()->data_len();
708 : }
709 :
710 0 : void Dhcpv6Handler::SendDhcpResponse() {
711 0 : UpdateStats();
712 : // In TSN, the source address for DHCP response should be the address
713 : // in the subnet reserved for service node. Otherwise, it will be the
714 : // GW address. dns_addr field has this address, use it as the source IP.
715 0 : FillDhcpResponse(MacAddress(pkt_info_->eth->ether_shost),
716 0 : config_.dns_addr.to_v6(),
717 0 : pkt_info_->ip_saddr.to_v6());
718 : uint32_t interface =
719 0 : (pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) ?
720 0 : pkt_info_->agent_hdr.cmd_param : GetInterfaceIndex();
721 : uint16_t command =
722 0 : (pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) ?
723 0 : (uint16_t)AgentHdr::TX_ROUTE : AgentHdr::TX_SWITCH;
724 0 : Send(interface, pkt_info_->vrf, command, PktHandler::DHCPV6);
725 0 : }
726 :
727 0 : void Dhcpv6Handler::UpdateStats() {
728 0 : Dhcpv6Proto *dhcp_proto = agent()->dhcpv6_proto();
729 0 : (out_msg_type_ == DHCPV6_ADVERTISE) ? dhcp_proto->IncrStatsAdvertise() :
730 0 : dhcp_proto->IncrStatsReply();
731 0 : }
732 :
733 : Dhcpv6Handler::DhcpOptionCategory
734 0 : Dhcpv6Handler::OptionCategory(uint32_t option) const {
735 0 : Dhcpv6CategoryIter iter = g_dhcpv6_category_map.find(option);
736 0 : if (iter == g_dhcpv6_category_map.end())
737 0 : return None;
738 0 : return iter->second;
739 : }
740 :
741 0 : uint32_t Dhcpv6Handler::OptionCode(const std::string &option) const {
742 : Dhcpv6NameCodeIter iter =
743 0 : g_dhcpv6_namecode_map.find(boost::to_lower_copy(option));
744 0 : return (iter == g_dhcpv6_namecode_map.end()) ? 0 : iter->second;
745 : }
746 :
747 0 : void Dhcpv6Handler::DhcpTrace(const std::string &msg) const {
748 0 : DHCPV6_TRACE(Error, "VM " << config_.ip_addr.to_string() << " : " << msg);
749 0 : }
|