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