2 * Copyright (c) 2008, 2009 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"
25 #include "dhcp-client.h"
29 #include "openflow/openflow.h"
32 #include "vconn-ssl.h"
34 #define THIS_MODULE VLM_discovery
39 bool update_resolv_conf
;
41 struct dhclient
*dhcp
;
43 struct status_category
*ss_cat
;
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_status_cb(struct status_reply
*sr
, void *d_
)
54 struct discovery
*d
= d_
;
56 status_reply_put(sr
, "accept-remote=%s", d
->re
);
57 status_reply_put(sr
, "n-changes=%d", d
->n_changes
);
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
);
67 const struct dhcp_msg
*cfg
= dhclient_get_config(d
->dhcp
);
72 status_reply_put(sr
, "ip="IP_FMT
, IP_ARGS(&ip
));
73 status_reply_put(sr
, "netmask="IP_FMT
, IP_ARGS(&netmask
));
75 status_reply_put(sr
, "router="IP_FMT
, IP_ARGS(&router
));
78 for (i
= 0; dhcp_msg_get_ip(cfg
, DHCP_CODE_DNS_SERVER
, i
,
81 status_reply_put(sr
, "dns%d="IP_FMT
, i
, IP_ARGS(&dns_server
));
84 domain_name
= dhcp_msg_get_string(cfg
, DHCP_CODE_DOMAIN_NAME
);
86 status_reply_put(sr
, "domain=%s", domain_name
);
90 status_reply_put(sr
, "lease-remaining=%u",
91 dhclient_get_lease_remaining(d
->dhcp
));
97 discovery_create(const char *re
, bool update_resolv_conf
,
98 struct dpif
*dpif
, struct switch_status
*ss
,
99 struct discovery
**discoveryp
)
102 char local_name
[IF_NAMESIZE
];
105 d
= xzalloc(sizeof *d
);
107 /* Controller regular expression. */
108 error
= discovery_set_accept_controller_re(d
, re
);
112 d
->update_resolv_conf
= update_resolv_conf
;
114 /* Initialize DHCP client. */
115 error
= dpif_port_get_name(dpif
, ODPP_LOCAL
,
116 local_name
, sizeof local_name
);
118 VLOG_ERR("failed to query datapath local port: %s", strerror(error
));
121 error
= dhclient_create(local_name
, modify_dhcp_request
,
122 validate_dhcp_offer
, d
, &d
->dhcp
);
124 VLOG_ERR("failed to initialize DHCP client: %s", strerror(error
));
127 dhclient_set_max_timeout(d
->dhcp
, 3);
128 dhclient_init(d
->dhcp
, 0);
130 d
->ss_cat
= switch_status_register(ss
, "discovery",
131 discovery_status_cb
, d
);
146 discovery_destroy(struct discovery
*d
)
152 dhclient_destroy(d
->dhcp
);
153 switch_status_unregister(d
->ss_cat
);
159 discovery_set_update_resolv_conf(struct discovery
*d
,
160 bool update_resolv_conf
)
162 d
->update_resolv_conf
= update_resolv_conf
;
166 discovery_set_accept_controller_re(struct discovery
*d
, const char *re_
)
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
);
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
);
198 discovery_question_connectivity(struct discovery
*d
)
201 dhclient_force_renew(d
->dhcp
, 15);
206 discovery_run(struct discovery
*d
, char **controller_name
)
209 *controller_name
= NULL
;
213 dhclient_run(d
->dhcp
);
214 if (!dhclient_changed(d
->dhcp
)) {
218 dhclient_configure_netdev(d
->dhcp
);
219 if (d
->update_resolv_conf
) {
220 dhclient_update_resolv_conf(d
->dhcp
);
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
);
229 *controller_name
= NULL
;
231 VLOG_INFO("discovered controller no longer available");
239 discovery_wait(struct discovery
*d
)
242 dhclient_wait(d
->dhcp
);
247 modify_dhcp_request(struct dhcp_msg
*msg
, void *aux UNUSED
)
249 dhcp_msg_put_string(msg
, DHCP_CODE_VENDOR_CLASS
, "OpenFlow");
253 validate_dhcp_offer(const struct dhcp_msg
*msg
, void *d_
)
255 const struct discovery
*d
= d_
;
259 vconn_name
= dhcp_msg_get_string(msg
, DHCP_CODE_OFP_CONTROLLER_VCONN
);
261 VLOG_WARN_RL(&rl
, "rejecting DHCP offer missing controller vconn");
264 accept
= !regexec(d
->regex
, vconn_name
, 0, NULL
, 0);
266 VLOG_WARN_RL(&rl
, "rejecting controller vconn that fails to match %s",