]> git.proxmox.com Git - mirror_ovs.git/blame - ofproto/discovery.c
treewide: Remove trailing whitespace
[mirror_ovs.git] / ofproto / discovery.c
CommitLineData
064af421 1/*
67a4917b 2 * Copyright (c) 2008, 2009, 2010 Nicira Networks.
064af421 3 *
a14bc59f
BP
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:
064af421 7 *
a14bc59f
BP
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
064af421
BP
15 */
16
17#include <config.h>
18#include "discovery.h"
19#include <errno.h>
20#include <inttypes.h>
9d82ec47 21#include <sys/socket.h>
064af421
BP
22#include <net/if.h>
23#include <regex.h>
24#include <stdlib.h>
25#include <string.h>
26#include "dhcp-client.h"
27#include "dhcp.h"
28#include "dpif.h"
29#include "netdev.h"
30#include "openflow/openflow.h"
31#include "packets.h"
32#include "status.h"
fe55ad15 33#include "stream-ssl.h"
064af421
BP
34#include "vlog.h"
35
5136ce49
BP
36VLOG_DEFINE_THIS_MODULE(discovery)
37
064af421 38struct discovery {
c2e01f64 39 char *dpif_name;
064af421
BP
40 char *re;
41 bool update_resolv_conf;
42 regex_t *regex;
43 struct dhclient *dhcp;
44 int n_changes;
45 struct status_category *ss_cat;
46};
47
48static void modify_dhcp_request(struct dhcp_msg *, void *aux);
49static bool validate_dhcp_offer(const struct dhcp_msg *, void *aux);
50
51static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60);
52
53static void
54discovery_status_cb(struct status_reply *sr, void *d_)
55{
56 struct discovery *d = d_;
57
58 status_reply_put(sr, "accept-remote=%s", d->re);
59 status_reply_put(sr, "n-changes=%d", d->n_changes);
60 if (d->dhcp) {
61 status_reply_put(sr, "state=%s", dhclient_get_state(d->dhcp));
62 status_reply_put(sr, "state-elapsed=%u",
d295e8e9 63 dhclient_get_state_elapsed(d->dhcp));
064af421
BP
64 if (dhclient_is_bound(d->dhcp)) {
65 uint32_t ip = dhclient_get_ip(d->dhcp);
66 uint32_t netmask = dhclient_get_netmask(d->dhcp);
67 uint32_t router = dhclient_get_router(d->dhcp);
68
69 const struct dhcp_msg *cfg = dhclient_get_config(d->dhcp);
70 uint32_t dns_server;
71 char *domain_name;
72 int i;
73
74 status_reply_put(sr, "ip="IP_FMT, IP_ARGS(&ip));
75 status_reply_put(sr, "netmask="IP_FMT, IP_ARGS(&netmask));
76 if (router) {
77 status_reply_put(sr, "router="IP_FMT, IP_ARGS(&router));
78 }
79
80 for (i = 0; dhcp_msg_get_ip(cfg, DHCP_CODE_DNS_SERVER, i,
81 &dns_server);
82 i++) {
83 status_reply_put(sr, "dns%d="IP_FMT, i, IP_ARGS(&dns_server));
84 }
85
86 domain_name = dhcp_msg_get_string(cfg, DHCP_CODE_DOMAIN_NAME);
87 if (domain_name) {
88 status_reply_put(sr, "domain=%s", domain_name);
89 free(domain_name);
90 }
91
92 status_reply_put(sr, "lease-remaining=%u",
93 dhclient_get_lease_remaining(d->dhcp));
94 }
95 }
96}
97
98int
99discovery_create(const char *re, bool update_resolv_conf,
100 struct dpif *dpif, struct switch_status *ss,
101 struct discovery **discoveryp)
102{
103 struct discovery *d;
104 char local_name[IF_NAMESIZE];
105 int error;
106
ec6fde61 107 d = xzalloc(sizeof *d);
064af421 108
c2e01f64
BP
109 d->dpif_name = xstrdup(dpif_base_name(dpif));
110
064af421
BP
111 /* Controller regular expression. */
112 error = discovery_set_accept_controller_re(d, re);
113 if (error) {
114 goto error_free;
115 }
116 d->update_resolv_conf = update_resolv_conf;
117
118 /* Initialize DHCP client. */
335562c0
BP
119 error = dpif_port_get_name(dpif, ODPP_LOCAL,
120 local_name, sizeof local_name);
064af421 121 if (error) {
c2e01f64
BP
122 VLOG_ERR("%s: failed to query datapath local port: %s",
123 d->dpif_name, strerror(error));
064af421
BP
124 goto error_regfree;
125 }
126 error = dhclient_create(local_name, modify_dhcp_request,
127 validate_dhcp_offer, d, &d->dhcp);
128 if (error) {
c2e01f64
BP
129 VLOG_ERR("%s: failed to initialize DHCP client: %s",
130 d->dpif_name, strerror(error));
064af421
BP
131 goto error_regfree;
132 }
133 dhclient_set_max_timeout(d->dhcp, 3);
134 dhclient_init(d->dhcp, 0);
135
136 d->ss_cat = switch_status_register(ss, "discovery",
137 discovery_status_cb, d);
138
139 *discoveryp = d;
140 return 0;
141
142error_regfree:
143 regfree(d->regex);
144 free(d->regex);
145error_free:
c2e01f64 146 free(d->dpif_name);
064af421
BP
147 free(d);
148 *discoveryp = 0;
149 return error;
150}
151
152void
153discovery_destroy(struct discovery *d)
154{
155 if (d) {
156 free(d->re);
157 regfree(d->regex);
158 free(d->regex);
159 dhclient_destroy(d->dhcp);
160 switch_status_unregister(d->ss_cat);
c2e01f64 161 free(d->dpif_name);
064af421
BP
162 free(d);
163 }
164}
165
79c9f2ee
BP
166bool
167discovery_get_update_resolv_conf(const struct discovery *d)
168{
169 return d->update_resolv_conf;
170}
171
064af421
BP
172void
173discovery_set_update_resolv_conf(struct discovery *d,
174 bool update_resolv_conf)
175{
176 d->update_resolv_conf = update_resolv_conf;
177}
178
79c9f2ee
BP
179const char *
180discovery_get_accept_controller_re(const struct discovery *d)
181{
182 return d->re;
183}
184
064af421
BP
185int
186discovery_set_accept_controller_re(struct discovery *d, const char *re_)
187{
188 regex_t *regex;
189 int error;
190 char *re;
191
fe55ad15 192 re = (!re_ ? xstrdup(stream_ssl_is_configured() ? "^ssl:.*" : "^tcp:.*")
064af421
BP
193 : re_[0] == '^' ? xstrdup(re_) : xasprintf("^%s", re_));
194 regex = xmalloc(sizeof *regex);
195 error = regcomp(regex, re, REG_NOSUB | REG_EXTENDED);
196 if (error) {
197 size_t length = regerror(error, regex, NULL, 0);
198 char *buffer = xmalloc(length);
199 regerror(error, regex, buffer, length);
c2e01f64 200 VLOG_WARN("%s: %s: %s", d->dpif_name, re, buffer);
064af421
BP
201 free(regex);
202 free(re);
203 return EINVAL;
204 } else {
205 if (d->regex) {
206 regfree(d->regex);
207 free(d->regex);
208 }
209 free(d->re);
210
211 d->regex = regex;
212 d->re = re;
213 return 0;
214 }
215}
216
217void
218discovery_question_connectivity(struct discovery *d)
219{
220 if (d->dhcp) {
d295e8e9 221 dhclient_force_renew(d->dhcp, 15);
064af421
BP
222 }
223}
224
225bool
226discovery_run(struct discovery *d, char **controller_name)
227{
228 if (!d->dhcp) {
229 *controller_name = NULL;
230 return true;
231 }
232
233 dhclient_run(d->dhcp);
234 if (!dhclient_changed(d->dhcp)) {
235 return false;
236 }
237
238 dhclient_configure_netdev(d->dhcp);
239 if (d->update_resolv_conf) {
240 dhclient_update_resolv_conf(d->dhcp);
241 }
242
243 if (dhclient_is_bound(d->dhcp)) {
244 *controller_name = dhcp_msg_get_string(dhclient_get_config(d->dhcp),
245 DHCP_CODE_OFP_CONTROLLER_VCONN);
c2e01f64
BP
246 VLOG_INFO("%s: discovered controller %s",
247 d->dpif_name, *controller_name);
064af421
BP
248 d->n_changes++;
249 } else {
250 *controller_name = NULL;
251 if (d->n_changes) {
c2e01f64
BP
252 VLOG_INFO("%s: discovered controller no longer available",
253 d->dpif_name);
064af421
BP
254 d->n_changes++;
255 }
256 }
257 return true;
258}
259
260void
261discovery_wait(struct discovery *d)
262{
263 if (d->dhcp) {
d295e8e9 264 dhclient_wait(d->dhcp);
064af421
BP
265 }
266}
267
268static void
67a4917b 269modify_dhcp_request(struct dhcp_msg *msg, void *aux OVS_UNUSED)
064af421
BP
270{
271 dhcp_msg_put_string(msg, DHCP_CODE_VENDOR_CLASS, "OpenFlow");
272}
273
274static bool
275validate_dhcp_offer(const struct dhcp_msg *msg, void *d_)
276{
277 const struct discovery *d = d_;
278 char *vconn_name;
279 bool accept;
280
281 vconn_name = dhcp_msg_get_string(msg, DHCP_CODE_OFP_CONTROLLER_VCONN);
282 if (!vconn_name) {
c2e01f64
BP
283 VLOG_WARN_RL(&rl, "%s: rejecting DHCP offer missing controller vconn",
284 d->dpif_name);
064af421
BP
285 return false;
286 }
287 accept = !regexec(d->regex, vconn_name, 0, NULL, 0);
288 if (!accept) {
c2e01f64
BP
289 VLOG_WARN_RL(&rl, "%s: rejecting controller vconn that fails to "
290 "match %s", d->dpif_name, d->re);
064af421
BP
291 }
292 free(vconn_name);
293 return accept;
294}