2 * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include "discovery.h"
21 #include <sys/socket.h>
26 #include "dhcp-client.h"
30 #include "openflow/openflow.h"
32 #include "stream-ssl.h"
35 VLOG_DEFINE_THIS_MODULE(discovery);
40 bool update_resolv_conf;
42 struct dhclient *dhcp;
46 static void modify_dhcp_request(struct dhcp_msg *, void *aux);
47 static bool validate_dhcp_offer(const struct dhcp_msg *, void *aux);
49 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60);
52 discovery_create(const char *re, bool update_resolv_conf,
53 struct dpif *dpif, struct discovery **discoveryp)
56 char local_name[IF_NAMESIZE];
59 d = xzalloc(sizeof *d);
61 d->dpif_name = xstrdup(dpif_base_name(dpif));
63 /* Controller regular expression. */
64 error = discovery_set_accept_controller_re(d, re);
68 d->update_resolv_conf = update_resolv_conf;
70 /* Initialize DHCP client. */
71 error = dpif_port_get_name(dpif, ODPP_LOCAL,
72 local_name, sizeof local_name);
74 VLOG_ERR("%s: failed to query datapath local port: %s",
75 d->dpif_name, strerror(error));
78 error = dhclient_create(local_name, modify_dhcp_request,
79 validate_dhcp_offer, d, &d->dhcp);
81 VLOG_ERR("%s: failed to initialize DHCP client: %s",
82 d->dpif_name, strerror(error));
85 dhclient_set_max_timeout(d->dhcp, 3);
86 dhclient_init(d->dhcp, 0);
102 discovery_destroy(struct discovery *d)
108 dhclient_destroy(d->dhcp);
115 discovery_get_update_resolv_conf(const struct discovery *d)
117 return d->update_resolv_conf;
121 discovery_set_update_resolv_conf(struct discovery *d,
122 bool update_resolv_conf)
124 d->update_resolv_conf = update_resolv_conf;
128 discovery_get_accept_controller_re(const struct discovery *d)
134 discovery_set_accept_controller_re(struct discovery *d, const char *re_)
140 re = (!re_ ? xstrdup(stream_ssl_is_configured() ? "^ssl:.*" : "^tcp:.*")
141 : re_[0] == '^' ? xstrdup(re_) : xasprintf("^%s", re_));
142 regex = xmalloc(sizeof *regex);
143 error = regcomp(regex, re, REG_NOSUB | REG_EXTENDED);
145 size_t length = regerror(error, regex, NULL, 0);
146 char *buffer = xmalloc(length);
147 regerror(error, regex, buffer, length);
148 VLOG_WARN("%s: %s: %s", d->dpif_name, re, buffer);
167 discovery_question_connectivity(struct discovery *d)
170 dhclient_force_renew(d->dhcp, 15);
175 discovery_run(struct discovery *d, char **controller_name)
178 *controller_name = NULL;
182 dhclient_run(d->dhcp);
183 if (!dhclient_changed(d->dhcp)) {
187 dhclient_configure_netdev(d->dhcp);
188 if (d->update_resolv_conf) {
189 dhclient_update_resolv_conf(d->dhcp);
192 if (dhclient_is_bound(d->dhcp)) {
193 *controller_name = dhcp_msg_get_string(dhclient_get_config(d->dhcp),
194 DHCP_CODE_OFP_CONTROLLER_VCONN);
195 VLOG_INFO("%s: discovered controller %s",
196 d->dpif_name, *controller_name);
199 *controller_name = NULL;
201 VLOG_INFO("%s: discovered controller no longer available",
210 discovery_wait(struct discovery *d)
213 dhclient_wait(d->dhcp);
218 modify_dhcp_request(struct dhcp_msg *msg, void *aux OVS_UNUSED)
220 dhcp_msg_put_string(msg, DHCP_CODE_VENDOR_CLASS, "OpenFlow");
224 validate_dhcp_offer(const struct dhcp_msg *msg, void *d_)
226 const struct discovery *d = d_;
230 vconn_name = dhcp_msg_get_string(msg, DHCP_CODE_OFP_CONTROLLER_VCONN);
232 VLOG_WARN_RL(&rl, "%s: rejecting DHCP offer missing controller vconn",
236 accept = !regexec(d->regex, vconn_name, 0, NULL, 0);
238 VLOG_WARN_RL(&rl, "%s: rejecting controller vconn that fails to "
239 "match %s", d->dpif_name, d->re);