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