2 * Copyright (c) 2008, 2009, 2010 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"
33 #include "stream-ssl.h"
35 #define THIS_MODULE VLM_discovery
40 bool update_resolv_conf;
42 struct dhclient *dhcp;
44 struct status_category *ss_cat;
47 static void modify_dhcp_request(struct dhcp_msg *, void *aux);
48 static bool validate_dhcp_offer(const struct dhcp_msg *, void *aux);
50 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60);
53 discovery_status_cb(struct status_reply *sr, void *d_)
55 struct discovery *d = d_;
57 status_reply_put(sr, "accept-remote=%s", d->re);
58 status_reply_put(sr, "n-changes=%d", d->n_changes);
60 status_reply_put(sr, "state=%s", dhclient_get_state(d->dhcp));
61 status_reply_put(sr, "state-elapsed=%u",
62 dhclient_get_state_elapsed(d->dhcp));
63 if (dhclient_is_bound(d->dhcp)) {
64 uint32_t ip = dhclient_get_ip(d->dhcp);
65 uint32_t netmask = dhclient_get_netmask(d->dhcp);
66 uint32_t router = dhclient_get_router(d->dhcp);
68 const struct dhcp_msg *cfg = dhclient_get_config(d->dhcp);
73 status_reply_put(sr, "ip="IP_FMT, IP_ARGS(&ip));
74 status_reply_put(sr, "netmask="IP_FMT, IP_ARGS(&netmask));
76 status_reply_put(sr, "router="IP_FMT, IP_ARGS(&router));
79 for (i = 0; dhcp_msg_get_ip(cfg, DHCP_CODE_DNS_SERVER, i,
82 status_reply_put(sr, "dns%d="IP_FMT, i, IP_ARGS(&dns_server));
85 domain_name = dhcp_msg_get_string(cfg, DHCP_CODE_DOMAIN_NAME);
87 status_reply_put(sr, "domain=%s", domain_name);
91 status_reply_put(sr, "lease-remaining=%u",
92 dhclient_get_lease_remaining(d->dhcp));
98 discovery_create(const char *re, bool update_resolv_conf,
99 struct dpif *dpif, struct switch_status *ss,
100 struct discovery **discoveryp)
103 char local_name[IF_NAMESIZE];
106 d = xzalloc(sizeof *d);
108 /* Controller regular expression. */
109 error = discovery_set_accept_controller_re(d, re);
113 d->update_resolv_conf = update_resolv_conf;
115 /* Initialize DHCP client. */
116 error = dpif_port_get_name(dpif, ODPP_LOCAL,
117 local_name, sizeof local_name);
119 VLOG_ERR("failed to query datapath local port: %s", strerror(error));
122 error = dhclient_create(local_name, modify_dhcp_request,
123 validate_dhcp_offer, d, &d->dhcp);
125 VLOG_ERR("failed to initialize DHCP client: %s", strerror(error));
128 dhclient_set_max_timeout(d->dhcp, 3);
129 dhclient_init(d->dhcp, 0);
131 d->ss_cat = switch_status_register(ss, "discovery",
132 discovery_status_cb, d);
147 discovery_destroy(struct discovery *d)
153 dhclient_destroy(d->dhcp);
154 switch_status_unregister(d->ss_cat);
160 discovery_get_update_resolv_conf(const struct discovery *d)
162 return d->update_resolv_conf;
166 discovery_set_update_resolv_conf(struct discovery *d,
167 bool update_resolv_conf)
169 d->update_resolv_conf = update_resolv_conf;
173 discovery_get_accept_controller_re(const struct discovery *d)
179 discovery_set_accept_controller_re(struct discovery *d, const char *re_)
185 re = (!re_ ? xstrdup(stream_ssl_is_configured() ? "^ssl:.*" : "^tcp:.*")
186 : re_[0] == '^' ? xstrdup(re_) : xasprintf("^%s", re_));
187 regex = xmalloc(sizeof *regex);
188 error = regcomp(regex, re, REG_NOSUB | REG_EXTENDED);
190 size_t length = regerror(error, regex, NULL, 0);
191 char *buffer = xmalloc(length);
192 regerror(error, regex, buffer, length);
193 VLOG_WARN("%s: %s", re, buffer);
211 discovery_question_connectivity(struct discovery *d)
214 dhclient_force_renew(d->dhcp, 15);
219 discovery_run(struct discovery *d, char **controller_name)
222 *controller_name = NULL;
226 dhclient_run(d->dhcp);
227 if (!dhclient_changed(d->dhcp)) {
231 dhclient_configure_netdev(d->dhcp);
232 if (d->update_resolv_conf) {
233 dhclient_update_resolv_conf(d->dhcp);
236 if (dhclient_is_bound(d->dhcp)) {
237 *controller_name = dhcp_msg_get_string(dhclient_get_config(d->dhcp),
238 DHCP_CODE_OFP_CONTROLLER_VCONN);
239 VLOG_INFO("%s: discovered controller", *controller_name);
242 *controller_name = NULL;
244 VLOG_INFO("discovered controller no longer available");
252 discovery_wait(struct discovery *d)
255 dhclient_wait(d->dhcp);
260 modify_dhcp_request(struct dhcp_msg *msg, void *aux OVS_UNUSED)
262 dhcp_msg_put_string(msg, DHCP_CODE_VENDOR_CLASS, "OpenFlow");
266 validate_dhcp_offer(const struct dhcp_msg *msg, void *d_)
268 const struct discovery *d = d_;
272 vconn_name = dhcp_msg_get_string(msg, DHCP_CODE_OFP_CONTROLLER_VCONN);
274 VLOG_WARN_RL(&rl, "rejecting DHCP offer missing controller vconn");
277 accept = !regexec(d->regex, vconn_name, 0, NULL, 0);
279 VLOG_WARN_RL(&rl, "rejecting controller vconn that fails to match %s",