I've never heard of anyone actually using controller discovery.
It adds a great deal of code to the source tree, and a little
bit of complication to ofproto, so this commit removes it.
contact the DHCP server until the secure channel has
started. The address will be obtained in step 7.
- - If you are using in-band control with controller discovery, no
- configuration is required at this point. You may proceed to
- the next step.
-
6. Run ovs-openflowd to start the secure channel connecting the datapath to
a remote controller. If the controller is running on host
192.168.1.2 port 6633 (the default port), the ovs-openflowd invocation
# ovs-openflowd dp0 tcp:192.168.1.2
- - If you are using in-band control with controller discovery, omit
- the second argument to the ovs-openflowd command.
-
- If you are using out-of-band control, add --out-of-band to the
command line.
in an insecure manner. Please see INSTALL.SSL for a description of
how to connect securely using SSL.
-7. If you are using in-band control with manual configuration, and the
- switch obtains its IP address dynamically, then you may now obtain
- the switch's IP address, e.g. by invoking a DHCP client. The
- secure channel will only be able to connect to the controller after
- an IP address has been obtained.
+7. If you are using in-band control, and the switch obtains its IP address
+ dynamically, then you may now obtain the switch's IP address, e.g. by
+ invoking a DHCP client. The secure channel will only be able to connect
+ to the controller after an IP address has been obtained.
8. The secure channel should connect to the controller within a few
- seconds. It may take a little longer if controller discovery is in
- use, because the switch must then also obtain its own IP address
- and the controller's location via DHCP.
+ seconds.
References
----------
* To (re)configure the controller, edit /etc/default/openvswitch-controller
and run "/etc/init.d/openvswitch-controller restart".
-* To enable OpenFlow switches to automatically discover the location
- of the controller, you must install and configure a DHCP server.
- The ovs-openflowd(8) manpage (found in the openvswitch-switch
- package) gives a working example configuration file for the ISC DHCP
- server.
-
- -- Ben Pfaff <blp@nicira.com>, Wed, 8 Jul 2009 09:39:53 -0700
+ -- Ben Pfaff <blp@nicira.com>, Fri, 4 Mar 2011 14:28:53 -0800
_debian/ovsdb/ovsdb-server usr/bin
-_debian/utilities/ovs-discover usr/sbin
_debian/utilities/ovs-dpctl usr/sbin
_debian/utilities/ovs-vsctl usr/sbin
_debian/utilities/ovs-pcap usr/bin
_debian/ovsdb/ovsdb-server.1
-_debian/utilities/ovs-discover.8
_debian/utilities/ovs-dpctl.8
_debian/utilities/ovs-pcap.1
_debian/utilities/ovs-tcpundump.1
lib/csum.h \
lib/daemon.c \
lib/daemon.h \
+ lib/dhcp.h \
lib/dummy.c \
lib/dummy.h \
- lib/dhcp-client.c \
- lib/dhcp-client.h \
- lib/dhcp.c \
- lib/dhcp.h \
lib/dhparams.h \
lib/dirs.h \
lib/dpif-netdev.c \
+++ /dev/null
-/*
- * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <config.h>
-#include "dhcp-client.h"
-#include <arpa/inet.h>
-#include <assert.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-#include "csum.h"
-#include "dhcp.h"
-#include "dynamic-string.h"
-#include "flow.h"
-#include "netdev.h"
-#include "ofpbuf.h"
-#include "poll-loop.h"
-#include "sat-math.h"
-#include "timeval.h"
-#include "vlog.h"
-
-VLOG_DEFINE_THIS_MODULE(dhcp_client);
-
-#define DHCLIENT_STATES \
- DHCLIENT_STATE(INIT, 1 << 0) \
- DHCLIENT_STATE(INIT_REBOOT, 1 << 1) \
- DHCLIENT_STATE(REBOOTING, 1 << 2) \
- DHCLIENT_STATE(SELECTING, 1 << 3) \
- DHCLIENT_STATE(REQUESTING, 1 << 4) \
- DHCLIENT_STATE(BOUND, 1 << 5) \
- DHCLIENT_STATE(RENEWING, 1 << 6) \
- DHCLIENT_STATE(REBINDING, 1 << 7) \
- DHCLIENT_STATE(RELEASED, 1 << 8)
-enum dhclient_state {
-#define DHCLIENT_STATE(NAME, VALUE) S_##NAME = VALUE,
- DHCLIENT_STATES
-#undef DHCLIENT_STATE
-};
-
-static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60);
-
-static const char *
-state_name(enum dhclient_state state)
-{
- switch (state) {
-#define DHCLIENT_STATE(NAME, VALUE) case S_##NAME: return #NAME;
- DHCLIENT_STATES
-#undef DHCLIENT_STATE
- }
- return "***ERROR***";
-}
-
-struct dhclient {
- /* Configuration. */
- struct netdev *netdev;
-
- void (*modify_request)(struct dhcp_msg *, void *aux);
- bool (*validate_offer)(const struct dhcp_msg *, void *aux);
- void *aux;
-
- /* DHCP state. */
- enum dhclient_state state;
- unsigned int state_entered; /* When we transitioned to this state. */
- uint32_t xid; /* In host byte order. */
- uint32_t ipaddr, netmask, router;
- uint32_t server_ip;
- struct dhcp_msg *binding;
- bool changed;
-
- unsigned int retransmit, delay; /* Used by send_reliably(). */
- unsigned int max_timeout;
-
- unsigned int init_delay; /* Used by S_INIT. */
-
- time_t lease_expiration;
- unsigned int bound_timeout;
- unsigned int renewing_timeout;
- unsigned int rebinding_timeout;
-
- /* Used by dhclient_run() and dhclient_wait() */
- unsigned int min_timeout;
- int received;
-
- /* Set when we send out a DHCPDISCOVER message. */
- uint32_t secs;
-
- struct ds s;
-};
-
-/* Minimum acceptable lease time, in seconds. */
-#define MIN_ACCEPTABLE_LEASE 15
-
-static void state_transition(struct dhclient *, enum dhclient_state);
-static unsigned int elapsed_in_this_state(const struct dhclient *cli);
-static bool timeout(struct dhclient *, unsigned int secs);
-
-static void dhclient_msg_init(struct dhclient *, enum dhcp_msg_type,
- struct dhcp_msg *);
-static void send_reliably(struct dhclient *cli,
- void (*make_packet)(struct dhclient *,
- struct dhcp_msg *));
-static bool do_receive_msg(struct dhclient *, struct dhcp_msg *);
-static void do_send_msg(struct dhclient *, const struct dhcp_msg *);
-static bool receive_ack(struct dhclient *);
-
-static unsigned int fuzz(unsigned int x, int max_fuzz);
-static unsigned int calc_t2(unsigned int lease);
-static unsigned int calc_t1(unsigned int lease, unsigned int t2);
-
-static unsigned int clamp(unsigned int x, unsigned int min, unsigned int max);
-
-/* Creates a new DHCP client to configure the network device 'netdev_name'
- * (e.g. "eth0").
- *
- * If 'modify_request' is non-null, then each DHCP message to discover or
- * request an address will be passed to it (along with auxiliary data 'aux').
- * It may then add any desired options to the message for transmission.
- *
- * If 'validate_offer' is non-null, then each DHCP message that offers an
- * address will be passed to it (along with auxiliary data 'aux') for
- * validation: if it returns true, the address will accepted; otherwise, it
- * will be rejected.
- *
- * The DHCP client will not start advertising for an IP address until
- * dhclient_init() is called.
- *
- * If successful, returns 0 and sets '*cli' to the new DHCP client. Otherwise,
- * returns a positive errno value and sets '*cli' to a null pointer. */
-int
-dhclient_create(const char *netdev_name,
- void (*modify_request)(struct dhcp_msg *, void *aux),
- bool (*validate_offer)(const struct dhcp_msg *, void *aux),
- void *aux, struct dhclient **cli_)
-{
- struct dhclient *cli;
- struct netdev_options netdev_options;
- struct netdev *netdev;
- int error;
-
- *cli_ = NULL;
-
- memset(&netdev_options, 0, sizeof netdev_options);
- netdev_options.name = netdev_name;
- netdev_options.ethertype = ETH_TYPE_IP;
-
- error = netdev_open(&netdev_options, &netdev);
- /* XXX install socket filter to catch only DHCP packets. */
- if (error) {
- VLOG_ERR("%s: could not open network device: %s",
- netdev_name, strerror(error));
- return error;
- }
-
- error = netdev_turn_flags_on(netdev, NETDEV_UP, false);
- if (error) {
- VLOG_ERR("%s: could not bring device up: %s",
- netdev_name, strerror(error));
- netdev_close(netdev);
- return error;
- }
-
- cli = xzalloc(sizeof *cli);
- cli->modify_request = modify_request;
- cli->validate_offer = validate_offer;
- cli->aux = aux;
- cli->netdev = netdev;
- cli->state = S_RELEASED;
- cli->state_entered = time_now();
- cli->xid = random_uint32();
- cli->ipaddr = 0;
- cli->server_ip = 0;
- cli->retransmit = cli->delay = 0;
- cli->max_timeout = 64;
- cli->min_timeout = 1;
- ds_init(&cli->s);
- cli->changed = true;
- *cli_ = cli;
- return 0;
-}
-
-/* Sets the maximum amount of timeout that 'cli' will wait for a reply from
- * the DHCP server before retransmitting, in seconds, to 'max_timeout'. The
- * default is 64 seconds. */
-void
-dhclient_set_max_timeout(struct dhclient *cli, unsigned int max_timeout)
-{
- cli->max_timeout = MAX(2, max_timeout);
-}
-
-/* Destroys 'cli' and frees all related resources. */
-void
-dhclient_destroy(struct dhclient *cli)
-{
- if (cli) {
- dhcp_msg_uninit(cli->binding);
- free(cli->binding);
- netdev_close(cli->netdev);
- ds_destroy(&cli->s);
- free(cli);
- }
-}
-
-/* Returns the network device in use by 'cli'. The caller must not destroy
- * the returned device. */
-struct netdev *
-dhclient_get_netdev(struct dhclient *cli)
-{
- return cli->netdev;
-}
-
-/* Returns the name of the network device in use by 'cli'. The caller must
- * not modify or destroy the returned string. */
-const char *
-dhclient_get_name(const struct dhclient *cli)
-{
- return netdev_get_name(cli->netdev);
-}
-
-/* Forces 'cli' into a (re)initialization state, in which no address is bound
- * but the client is advertising to obtain one. If 'requested_ip' is nonzero,
- * then the client will attempt to re-bind to that IP address; otherwise, it
- * will not ask for any particular address. */
-void
-dhclient_init(struct dhclient *cli, uint32_t requested_ip)
-{
- state_transition(cli, requested_ip ? S_INIT_REBOOT : S_INIT);
- cli->ipaddr = requested_ip;
- cli->min_timeout = 0;
- cli->init_delay = 0;
-}
-
-/* Forces 'cli' to release its bound IP address (if any). The client will not
- * advertise for a new address until dhclient_init() is called again. */
-void
-dhclient_release(struct dhclient *cli)
-{
- if (dhclient_is_bound(cli)) {
- struct dhcp_msg msg;
- dhclient_msg_init(cli, DHCPRELEASE, &msg);
- msg.ciaddr = cli->ipaddr;
- do_send_msg(cli, &msg);
- dhcp_msg_uninit(&msg);
- }
- state_transition(cli, S_RELEASED);
- cli->min_timeout = UINT_MAX;
-}
-
-static void
-do_force_renew(struct dhclient *cli, int deadline)
-{
- time_t now = time_now();
- unsigned int lease_left = sat_sub(cli->lease_expiration, now);
- if (lease_left <= deadline) {
- if (cli->state & (S_RENEWING | S_REBINDING)) {
- return;
- }
- deadline = lease_left;
- }
- if (cli->state & (S_BOUND | S_RENEWING)) {
- state_transition(cli, S_RENEWING);
- cli->renewing_timeout = deadline * 3 / 4;
- cli->rebinding_timeout = deadline * 1 / 4;
- } else {
- state_transition(cli, S_REBINDING);
- cli->rebinding_timeout = deadline;
- }
- cli->min_timeout = 0;
-}
-
-/* Forces 'cli' to attempt to renew the lease its current IP address (if any)
- * within 'deadline' seconds. If the deadline is not met, then the client
- * gives up its IP address binding and re-starts the DHCP process. */
-void
-dhclient_force_renew(struct dhclient *cli, int deadline)
-{
- /* Drain the receive queue so that we know that any DHCPACK we process is
- * freshly received. */
- netdev_drain(cli->netdev);
-
- switch (cli->state) {
- case S_INIT:
- case S_INIT_REBOOT:
- case S_REBOOTING:
- case S_SELECTING:
- case S_REQUESTING:
- break;
-
- case S_BOUND:
- case S_RENEWING:
- case S_REBINDING:
- do_force_renew(cli, deadline);
- break;
-
- case S_RELEASED:
- dhclient_init(cli, 0);
- break;
- }
-}
-
-/* Returns true if 'cli' is bound to an IP address, false otherwise. */
-bool
-dhclient_is_bound(const struct dhclient *cli)
-{
- return cli->state & (S_BOUND | S_RENEWING | S_REBINDING);
-}
-
-/* Returns true if 'cli' has changed from bound to unbound, or vice versa, at
- * least once since the last time this function was called. */
-bool
-dhclient_changed(struct dhclient *cli)
-{
- bool changed = cli->changed;
- cli->changed = 0;
- return changed;
-}
-
-/* Returns 'cli''s current state, as a string. The caller must not modify or
- * free the string. */
-const char *
-dhclient_get_state(const struct dhclient *cli)
-{
- return state_name(cli->state);
-}
-
-/* Returns the number of seconds spent so far in 'cli''s current state. */
-unsigned int
-dhclient_get_state_elapsed(const struct dhclient *cli)
-{
- return elapsed_in_this_state(cli);
-}
-
-/* If 'cli' is bound, returns the number of seconds remaining in its lease;
- * otherwise, returns 0. */
-unsigned int
-dhclient_get_lease_remaining(const struct dhclient *cli)
-{
- if (dhclient_is_bound(cli)) {
- time_t now = time_now();
- return cli->lease_expiration > now ? cli->lease_expiration - now : 0;
- } else {
- return 0;
- }
-}
-
-/* If 'cli' is bound to an IP address, returns that IP address; otherwise,
- * returns 0. */
-uint32_t
-dhclient_get_ip(const struct dhclient *cli)
-{
- return dhclient_is_bound(cli) ? cli->ipaddr : 0;
-}
-
-/* If 'cli' is bound to an IP address, returns the netmask for that IP address;
- * otherwise, returns 0. */
-uint32_t
-dhclient_get_netmask(const struct dhclient *cli)
-{
- return dhclient_is_bound(cli) ? cli->netmask : 0;
-}
-
-/* If 'cli' is bound to an IP address and 'cli' has a default gateway, returns
- * that default gateway; otherwise, returns 0. */
-uint32_t
-dhclient_get_router(const struct dhclient *cli)
-{
- return dhclient_is_bound(cli) ? cli->router : 0;
-}
-
-/* If 'cli' is bound to an IP address, returns the DHCP message that was
- * received to obtain that IP address (so that the caller can obtain additional
- * options from it). Otherwise, returns a null pointer. */
-const struct dhcp_msg *
-dhclient_get_config(const struct dhclient *cli)
-{
- return dhclient_is_bound(cli) ? cli->binding : NULL;
-}
-
-/* Configures the network device backing 'cli' to the network address and other
- * parameters obtained via DHCP. If no address is bound on 'cli', removes any
- * configured address from 'cli'.
- *
- * To use a dhclient as a regular DHCP client that binds and unbinds from IP
- * addresses in the usual fashion, call this function after dhclient_run() if
- * anything has changed, like so:
- *
- * dhclient_run(cli);
- * if (dhclient_changed(cli)) {
- * dhclient_configure_netdev(cli);
- * }
- *
- */
-int
-dhclient_configure_netdev(struct dhclient *cli)
-{
- const char *cli_name = dhclient_get_name(cli);
- struct in_addr addr = { dhclient_get_ip(cli) };
- struct in_addr mask = { dhclient_get_netmask(cli) };
- struct in_addr router = { dhclient_get_router(cli) };
- int error;
-
- error = netdev_set_in4(cli->netdev, addr, mask);
- if (error) {
- VLOG_ERR("%s: could not set address "IP_FMT"/"IP_FMT" (%s)",
- cli_name, IP_ARGS(&addr.s_addr), IP_ARGS(&mask.s_addr),
- strerror(error));
- }
-
- if (!error && router.s_addr) {
- error = netdev_add_router(cli->netdev, router);
- if (error) {
- VLOG_ERR("%s: failed to add default route to "IP_FMT" (%s)",
- cli_name, IP_ARGS(&router), strerror(error));
- }
- }
-
- return error;
-}
-
-/* If 'cli' is bound and the binding includes DNS domain parameters, updates
- * /etc/resolv.conf will be updated to match the received parameters. Returns
- * 0 if successful, otherwise a positive errno value. */
-int
-dhclient_update_resolv_conf(struct dhclient *cli)
-{
- const char *cli_name = dhclient_get_name(cli);
- uint32_t dns_server;
- char *domain_name;
- bool has_domain_name;
- char new_name[128];
- FILE *old, *new;
- int i;
-
- if (!dhclient_is_bound(cli)) {
- return 0;
- }
- if (!dhcp_msg_get_ip(cli->binding, DHCP_CODE_DNS_SERVER, 0, &dns_server)) {
- VLOG_DBG("%s: binding does not include any DNS servers", cli_name);
- return 0;
- }
-
- sprintf(new_name, "/etc/resolv.conf.tmp%ld", (long int) getpid());
- new = fopen(new_name, "w");
- if (!new) {
- VLOG_WARN("%s: could not create %s (%s)",
- cli_name, new_name, strerror(errno));
- return errno;
- }
-
- domain_name = dhcp_msg_get_string(cli->binding, DHCP_CODE_DOMAIN_NAME);
- has_domain_name = domain_name != NULL;
- if (domain_name) {
- if (strspn(domain_name, "-_.0123456789abcdefghijklmnopqrstuvwxyz"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ") == strlen(domain_name)) {
- fprintf(new, "domain %s\n", domain_name);
- } else {
- VLOG_WARN("%s: ignoring invalid domain name %s",
- cli_name, domain_name);
- has_domain_name = false;
- }
- } else {
- VLOG_DBG("%s: binding does not include domain name", cli_name);
- }
- free(domain_name);
-
- for (i = 0; dhcp_msg_get_ip(cli->binding, DHCP_CODE_DNS_SERVER,
- i, &dns_server); i++) {
- fprintf(new, "nameserver "IP_FMT"\n", IP_ARGS(&dns_server));
- }
-
- old = fopen("/etc/resolv.conf", "r");
- if (old) {
- char line[128];
-
- while (fgets(line, sizeof line, old)) {
- char *kw = xmemdup0(line, strcspn(line, " \t\r\n"));
- if (strcmp(kw, "nameserver")
- && (!has_domain_name
- || (strcmp(kw, "domain") && strcmp(kw, "search")))) {
- fputs(line, new);
- }
- free(kw);
- }
- fclose(old);
- } else {
- VLOG_DBG("%s: failed to open /etc/resolv.conf (%s)",
- cli_name, strerror(errno));
- }
-
- if (fclose(new) < 0) {
- VLOG_WARN("%s: closing %s failed (%s)",
- cli_name, new_name, strerror(errno));
- return errno;
- }
-
- if (rename(new_name, "/etc/resolv.conf") < 0) {
- VLOG_WARN("%s: failed to rename %s to /etc/resolv.conf (%s)",
- cli_name, new_name, strerror(errno));
- return errno;
- }
-
- return 0;
-}
-\f
-/* DHCP protocol. */
-
-static void
-make_dhcpdiscover(struct dhclient *cli, struct dhcp_msg *msg)
-{
- cli->secs = elapsed_in_this_state(cli);
- dhclient_msg_init(cli, DHCPDISCOVER, msg);
- if (cli->ipaddr) {
- dhcp_msg_put_ip(msg, DHCP_CODE_REQUESTED_IP, cli->ipaddr);
- }
-}
-
-static void
-make_dhcprequest(struct dhclient *cli, struct dhcp_msg *msg)
-{
- dhclient_msg_init(cli, DHCPREQUEST, msg);
- msg->ciaddr = dhclient_get_ip(cli);
- if (cli->state == S_REQUESTING) {
- dhcp_msg_put_ip(msg, DHCP_CODE_SERVER_IDENTIFIER, cli->server_ip);
- }
- dhcp_msg_put_ip(msg, DHCP_CODE_REQUESTED_IP, cli->ipaddr);
-}
-
-static void
-do_init(struct dhclient *cli, enum dhclient_state next_state)
-{
- if (!cli->init_delay) {
- cli->init_delay = fuzz(2, 1);
- }
- if (timeout(cli, cli->init_delay)) {
- state_transition(cli, next_state);
- }
-}
-
-static void
-dhclient_run_INIT(struct dhclient *cli)
-{
- do_init(cli, S_SELECTING);
-}
-
-static void
-dhclient_run_INIT_REBOOT(struct dhclient *cli)
-{
- do_init(cli, S_REBOOTING);
-}
-
-static void
-dhclient_run_REBOOTING(struct dhclient *cli)
-{
- send_reliably(cli, make_dhcprequest);
- if (!receive_ack(cli) && timeout(cli, 60)) {
- state_transition(cli, S_INIT);
- }
-}
-
-static bool
-dhcp_receive(struct dhclient *cli, unsigned int msgs, struct dhcp_msg *msg)
-{
- while (do_receive_msg(cli, msg)) {
- const char *cli_name = dhclient_get_name(cli);
-
- if (msg->type > 31 || !((1u << msg->type) & msgs)) {
- VLOG_DBG_RL(&rl, "%s: received unexpected %s in %s state: %s",
- cli_name,
- dhcp_type_name(msg->type), state_name(cli->state),
- dhcp_msg_to_string(msg, false, &cli->s));
- } else if (msg->xid != cli->xid) {
- VLOG_DBG_RL(&rl, "%s: ignoring %s with xid != %08"PRIx32" "
- "in %s state: %s", cli_name,
- dhcp_type_name(msg->type), msg->xid,
- state_name(cli->state),
- dhcp_msg_to_string(msg, false, &cli->s));
- } else {
- return true;
- }
- dhcp_msg_uninit(msg);
- }
- return false;
-}
-
-static bool
-validate_offered_options(struct dhclient *cli, const struct dhcp_msg *msg)
-{
- const char *cli_name = dhclient_get_name(cli);
- uint32_t lease, netmask;
-
- if (!dhcp_msg_get_secs(msg, DHCP_CODE_LEASE_TIME, 0, &lease)) {
- VLOG_WARN_RL(&rl, "%s: %s lacks lease time (%s)",
- cli_name, dhcp_type_name(msg->type),
- dhcp_msg_to_string(msg, false, &cli->s));
- } else if (!dhcp_msg_get_ip(msg, DHCP_CODE_SUBNET_MASK, 0, &netmask)) {
- VLOG_WARN_RL(&rl, "%s: %s lacks netmask (%s)",
- cli_name, dhcp_type_name(msg->type),
- dhcp_msg_to_string(msg, false, &cli->s));
- } else if (lease < MIN_ACCEPTABLE_LEASE) {
- VLOG_WARN_RL(&rl, "%s: ignoring %s with %"PRIu32"-second "
- "lease time (%s)", cli_name,
- dhcp_type_name(msg->type), lease,
- dhcp_msg_to_string(msg, false, &cli->s));
- } else if (cli->validate_offer && !cli->validate_offer(msg, cli->aux)) {
- VLOG_DBG_RL(&rl, "%s: client validation hook refused offer (%s)",
- cli_name, dhcp_msg_to_string(msg, false, &cli->s));
- } else {
- return true;
- }
- return false;
-}
-
-static void
-dhclient_run_SELECTING(struct dhclient *cli)
-{
- const char *cli_name = dhclient_get_name(cli);
- struct dhcp_msg msg;
-
- send_reliably(cli, make_dhcpdiscover);
- if (cli->server_ip && timeout(cli, 60)) {
- cli->server_ip = 0;
- state_transition(cli, S_INIT);
- }
- for (; dhcp_receive(cli, 1u << DHCPOFFER, &msg); dhcp_msg_uninit(&msg)) {
- if (!validate_offered_options(cli, &msg)) {
- continue;
- }
- if (!dhcp_msg_get_ip(&msg, DHCP_CODE_SERVER_IDENTIFIER,
- 0, &cli->server_ip)) {
- VLOG_WARN_RL(&rl, "%s: DHCPOFFER lacks server identifier (%s)",
- cli_name, dhcp_msg_to_string(&msg, false, &cli->s));
- continue;
- }
-
- VLOG_DBG_RL(&rl, "%s: accepting DHCPOFFER (%s)",
- cli_name, dhcp_msg_to_string(&msg, false, &cli->s));
- cli->ipaddr = msg.yiaddr;
- state_transition(cli, S_REQUESTING);
- break;
- }
-}
-
-static bool
-same_binding(const char *cli_name,
- const struct dhcp_msg *old, const struct dhcp_msg *new)
-{
- static const int codes[] = {
- DHCP_CODE_SUBNET_MASK,
- DHCP_CODE_ROUTER,
- DHCP_CODE_DNS_SERVER,
- DHCP_CODE_HOST_NAME,
- DHCP_CODE_DOMAIN_NAME,
- DHCP_CODE_IP_TTL,
- DHCP_CODE_MTU,
- DHCP_CODE_BROADCAST_ADDRESS,
- DHCP_CODE_STATIC_ROUTE,
- DHCP_CODE_ARP_CACHE_TIMEOUT,
- DHCP_CODE_ETHERNET_ENCAPSULATION,
- DHCP_CODE_TCP_TTL,
- DHCP_CODE_SERVER_IDENTIFIER,
- DHCP_CODE_OFP_CONTROLLER_VCONN,
- DHCP_CODE_OFP_PKI_URI,
- };
- int i;
- bool same = true;
-
- if (old->yiaddr != new->yiaddr) {
- VLOG_WARN("%s: DHCP binding changed IP address "
- "from "IP_FMT" to "IP_FMT,
- cli_name, IP_ARGS(&old->yiaddr), IP_ARGS(&new->yiaddr));
- same = false;
- }
- for (i = 0; i < ARRAY_SIZE(codes); i++) {
- int code = codes[i];
- const struct dhcp_option *old_opt = &old->options[code];
- const struct dhcp_option *new_opt = &new->options[code];
- if (!dhcp_option_equals(old_opt, new_opt)) {
- struct ds old_string = DS_EMPTY_INITIALIZER;
- struct ds new_string = DS_EMPTY_INITIALIZER;
- VLOG_WARN("%s: DHCP binding changed option from %s to %s",
- cli_name,
- dhcp_option_to_string(old_opt, code, &old_string),
- dhcp_option_to_string(new_opt, code, &new_string));
- ds_destroy(&old_string);
- ds_destroy(&new_string);
- same = false;
- }
- }
- return same;
-}
-
-static bool
-receive_ack(struct dhclient *cli)
-{
- struct dhcp_msg msg;
-
- if (!dhcp_receive(cli, (1u << DHCPACK) | (1u << DHCPNAK), &msg)) {
- return false;
- } else if (msg.type == DHCPNAK) {
- dhcp_msg_uninit(&msg);
- state_transition(cli, S_INIT);
- return true;
- } else if (!validate_offered_options(cli, &msg)) {
- dhcp_msg_uninit(&msg);
- return false;
- } else {
- uint32_t lease = 0, t1 = 0, t2 = 0;
-
- if (cli->binding) {
- if (!same_binding(dhclient_get_name(cli), cli->binding, &msg)) {
- cli->changed = true;
- }
- dhcp_msg_uninit(cli->binding);
- } else {
- cli->binding = xmalloc(sizeof *cli->binding);
- }
- dhcp_msg_copy(cli->binding, &msg);
-
- dhcp_msg_get_secs(&msg, DHCP_CODE_LEASE_TIME, 0, &lease);
- dhcp_msg_get_secs(&msg, DHCP_CODE_T1, 0, &t1);
- dhcp_msg_get_secs(&msg, DHCP_CODE_T2, 0, &t2);
- assert(lease >= MIN_ACCEPTABLE_LEASE);
-
- if (!t2 || t2 >= lease) {
- t2 = calc_t2(lease);
- }
- if (!t1 || t1 >= t2) {
- t1 = calc_t1(lease, t2);
- }
-
- cli->lease_expiration = sat_add(time_now(), lease);
- cli->bound_timeout = t1;
- cli->renewing_timeout = t2 - t1;
- cli->rebinding_timeout = lease - t2;
-
- cli->ipaddr = msg.yiaddr;
- dhcp_msg_get_ip(&msg, DHCP_CODE_SUBNET_MASK, 0, &cli->netmask);
- if (!dhcp_msg_get_ip(&msg, DHCP_CODE_ROUTER, 0, &cli->router)) {
- cli->router = INADDR_ANY;
- }
- state_transition(cli, S_BOUND);
- VLOG_DBG("%s: bound (%s)", dhclient_get_name(cli),
- dhcp_msg_to_string(&msg, false, &cli->s));
- return true;
- }
-}
-
-static void
-dhclient_run_REQUESTING(struct dhclient *cli)
-{
- send_reliably(cli, make_dhcprequest);
- if (!receive_ack(cli) && timeout(cli, 60)) {
- state_transition(cli, S_INIT);
- }
-}
-
-static void
-dhclient_run_BOUND(struct dhclient *cli)
-{
- if (timeout(cli, cli->bound_timeout)) {
- state_transition(cli, S_RENEWING);
- }
-}
-
-static void
-dhclient_run_RENEWING(struct dhclient *cli)
-{
- send_reliably(cli, make_dhcprequest);
- if (!receive_ack(cli) && timeout(cli, cli->renewing_timeout)) {
- state_transition(cli, S_REBINDING);
- }
-}
-
-static void
-dhclient_run_REBINDING(struct dhclient *cli)
-{
- send_reliably(cli, make_dhcprequest);
- if (!receive_ack(cli) && timeout(cli, cli->rebinding_timeout)) {
- state_transition(cli, S_INIT);
- }
-}
-
-static void
-dhclient_run_RELEASED(struct dhclient *cli OVS_UNUSED)
-{
- /* Nothing to do. */
-}
-
-/* Processes the DHCP protocol for 'cli'. */
-void
-dhclient_run(struct dhclient *cli)
-{
- int old_state;
- do {
- old_state = cli->state;
- cli->min_timeout = UINT_MAX;
- cli->received = 0;
- switch (cli->state) {
-#define DHCLIENT_STATE(NAME, VALUE) \
- case S_##NAME: dhclient_run_##NAME(cli); break;
- DHCLIENT_STATES
-#undef DHCLIENT_STATE
- default:
- NOT_REACHED();
- }
- } while (cli->state != old_state);
-}
-
-/* Sets up poll timeouts to wake up the poll loop when 'cli' needs to do some
- * work. */
-void
-dhclient_wait(struct dhclient *cli)
-{
- if (cli->min_timeout != UINT_MAX) {
- long long int wake = sat_add(cli->state_entered, cli->min_timeout);
- poll_timer_wait_until(wake * 1000);
- }
- /* Reset timeout to 1 second. This will have no effect ordinarily, because
- * dhclient_run() will typically set it back to a higher value. If,
- * however, the caller fails to call dhclient_run() before its next call to
- * dhclient_wait() we won't potentially block forever. */
- cli->min_timeout = 1;
-
- if (cli->state & (S_SELECTING | S_REQUESTING | S_RENEWING | S_REBINDING)) {
- netdev_recv_wait(cli->netdev);
- }
-}
-
-static void
-state_transition(struct dhclient *cli, enum dhclient_state state)
-{
- const char *cli_name = dhclient_get_name(cli);
- bool was_bound = dhclient_is_bound(cli);
- bool am_bound;
-
- if (cli->state != state) {
- VLOG_DBG("%s: entering %s", cli_name, state_name(state));
- cli->state = state;
- }
- cli->state_entered = time_now();
- cli->retransmit = cli->delay = 0;
- am_bound = dhclient_is_bound(cli);
- if (was_bound != am_bound) {
- cli->changed = true;
- if (am_bound) {
- assert(cli->binding != NULL);
- VLOG_INFO("%s: obtained address "IP_FMT", netmask "IP_FMT,
- cli_name,
- IP_ARGS(&cli->ipaddr), IP_ARGS(&cli->netmask));
- if (cli->router) {
- VLOG_INFO("%s: obtained default gateway "IP_FMT,
- cli_name, IP_ARGS(&cli->router));
- }
- } else {
- dhcp_msg_uninit(cli->binding);
- free(cli->binding);
- cli->binding = NULL;
-
- VLOG_INFO("%s: network address unbound", cli_name);
- }
- }
- if (cli->state & (S_SELECTING | S_REQUESTING | S_REBOOTING)) {
- netdev_drain(cli->netdev);
- }
-}
-
-static void
-send_reliably(struct dhclient *cli,
- void (*make_packet)(struct dhclient *, struct dhcp_msg *))
-{
- if (timeout(cli, cli->retransmit)) {
- struct dhcp_msg msg;
- make_packet(cli, &msg);
- if (cli->modify_request) {
- cli->modify_request(&msg, cli->aux);
- }
- do_send_msg(cli, &msg);
- cli->delay = MIN(cli->max_timeout, MAX(4, cli->delay * 2));
- cli->retransmit += fuzz(cli->delay, 1);
- dhcp_msg_uninit(&msg);
- }
-}
-
-static void
-dhclient_msg_init(struct dhclient *cli, enum dhcp_msg_type type,
- struct dhcp_msg *msg)
-{
- dhcp_msg_init(msg);
- msg->op = DHCP_BOOTREQUEST;
- msg->xid = cli->xid;
- msg->secs = cli->secs;
- msg->type = type;
- netdev_get_etheraddr(cli->netdev, msg->chaddr);
-}
-
-/* If time goes backward this returns a large number, which makes it look like
- * we've been in the current state a very long time. That's probably
- * fine for that corner case--we'll just expire our lease, etc., and try to
- * get a new one. */
-static unsigned int
-elapsed_in_this_state(const struct dhclient *cli)
-{
- return time_now() - cli->state_entered;
-}
-
-static bool
-timeout(struct dhclient *cli, unsigned int secs)
-{
- cli->min_timeout = MIN(cli->min_timeout, secs);
- return time_now() >= sat_add(cli->state_entered, secs);
-}
-
-static bool
-do_receive_msg(struct dhclient *cli, struct dhcp_msg *msg)
-{
- const char *cli_name = dhclient_get_name(cli);
- uint8_t cli_mac[ETH_ADDR_LEN];
- struct ofpbuf b;
-
- ofpbuf_init(&b, ETH_TOTAL_MAX + VLAN_ETH_HEADER_LEN);
- netdev_get_etheraddr(cli->netdev, cli_mac);
- for (; cli->received < 50; cli->received++) {
- const struct ip_header *ip;
- const struct dhcp_header *dhcp;
- struct flow flow;
- int error;
-
- ofpbuf_clear(&b);
- error = netdev_recv(cli->netdev, &b);
- if (error) {
- goto drained;
- }
-
- flow_extract(&b, 0, 0, &flow);
- if (flow.dl_type != htons(ETH_TYPE_IP)
- || flow.nw_proto != IPPROTO_UDP
- || flow.tp_dst != htons(DHCP_CLIENT_PORT)
- || !(eth_addr_is_broadcast(flow.dl_dst)
- || eth_addr_equals(flow.dl_dst, cli_mac))) {
- continue;
- }
-
- ip = b.l3;
- if (IP_IS_FRAGMENT(ip->ip_frag_off)) {
- /* We don't do reassembly. */
- VLOG_WARN_RL(&rl, "%s: ignoring fragmented DHCP datagram",
- cli_name);
- continue;
- }
-
- dhcp = b.l7;
- if (!dhcp) {
- VLOG_WARN_RL(&rl, "%s: ignoring DHCP datagram with missing "
- "payload", cli_name);
- continue;
- }
-
- ofpbuf_pull(&b, (char *)b.l7 - (char*)b.data);
- error = dhcp_parse(msg, &b);
- if (!error) {
- if (VLOG_IS_DBG_ENABLED()) {
- VLOG_DBG_RL(&rl, "%s: received %s", cli_name,
- dhcp_msg_to_string(msg, false, &cli->s));
- } else {
- VLOG_INFO_RL(&rl, "%s: received %s",
- cli_name, dhcp_type_name(msg->type));
- }
- ofpbuf_uninit(&b);
- return true;
- }
- }
- netdev_drain(cli->netdev);
-drained:
- ofpbuf_uninit(&b);
- return false;
-}
-
-static void
-do_send_msg(struct dhclient *cli, const struct dhcp_msg *msg)
-{
- const char *cli_name = dhclient_get_name(cli);
- struct ofpbuf b;
- struct eth_header eh;
- struct ip_header nh;
- struct udp_header th;
- uint32_t udp_csum;
- int error;
-
- ofpbuf_init(&b, ETH_TOTAL_MAX);
- ofpbuf_reserve(&b, ETH_HEADER_LEN + IP_HEADER_LEN + UDP_HEADER_LEN);
-
- dhcp_assemble(msg, &b);
-
- netdev_get_etheraddr(cli->netdev, eh.eth_src);
- memcpy(eh.eth_dst, eth_addr_broadcast, ETH_ADDR_LEN);
- eh.eth_type = htons(ETH_TYPE_IP);
-
- nh.ip_ihl_ver = IP_IHL_VER(5, IP_VERSION);
- nh.ip_tos = 0;
- nh.ip_tot_len = htons(IP_HEADER_LEN + UDP_HEADER_LEN + b.size);
- /* We can't guarantee uniqueness of ip_id versus the host's, screwing up
- * fragment reassembly, so prevent fragmentation and use an all-zeros
- * ip_id. RFC 791 doesn't say we can do this, but Linux does the same
- * thing for DF packets, so it must not screw anything up. */
- nh.ip_id = 0;
- nh.ip_frag_off = htons(IP_DONT_FRAGMENT);
- nh.ip_ttl = 64;
- nh.ip_proto = IPPROTO_UDP;
- nh.ip_csum = 0;
- nh.ip_src = dhclient_get_ip(cli);
- /* XXX need to use UDP socket for nonzero server IPs so that we can get
- * routing table support.
- *
- * if (...have server IP and in appropriate state...) {
- * nh.ip_dst = cli->server_ip;
- * } else {
- * nh.ip_dst = INADDR_BROADCAST;
- * }
- */
- nh.ip_dst = INADDR_BROADCAST;
- nh.ip_csum = csum(&nh, sizeof nh);
-
- th.udp_src = htons(DHCP_CLIENT_PORT);
- th.udp_dst = htons(DHCP_SERVER_PORT);
- th.udp_len = htons(UDP_HEADER_LEN + b.size);
- th.udp_csum = 0;
- udp_csum = csum_add32(0, nh.ip_src);
- udp_csum = csum_add32(udp_csum, nh.ip_dst);
- udp_csum = csum_add16(udp_csum, IPPROTO_UDP << 8);
- udp_csum = csum_add16(udp_csum, th.udp_len);
- udp_csum = csum_continue(udp_csum, &th, sizeof th);
- th.udp_csum = csum_finish(csum_continue(udp_csum, b.data, b.size));
-
- ofpbuf_push(&b, &th, sizeof th);
- ofpbuf_push(&b, &nh, sizeof nh);
- ofpbuf_push(&b, &eh, sizeof eh);
-
- /* Don't try to send the frame if it's too long for an Ethernet frame. We
- * disregard the network device's actual MTU because we don't want the
- * frame to have to be discarded or fragmented if it travels over a regular
- * Ethernet at some point. 1500 bytes should be enough for anyone. */
- if (b.size <= ETH_TOTAL_MAX) {
- if (VLOG_IS_DBG_ENABLED()) {
- VLOG_DBG("%s: sending %s",
- cli_name, dhcp_msg_to_string(msg, false, &cli->s));
- } else {
- VLOG_INFO("%s: sending %s", cli_name, dhcp_type_name(msg->type));
- }
- error = netdev_send(cli->netdev, &b);
- if (error) {
- VLOG_ERR("%s: send failed on %s (%s)", cli_name,
- netdev_get_name(cli->netdev), strerror(error));
- }
- } else {
- VLOG_ERR("%s: cannot send %zu-byte Ethernet frame", cli_name, b.size);
- }
-
- ofpbuf_uninit(&b);
-}
-
-static unsigned int
-fuzz(unsigned int x, int max_fuzz)
-{
- /* Generate number in range [-max_fuzz, +max_fuzz]. */
- int fuzz = random_range(max_fuzz * 2 + 1) - max_fuzz;
- unsigned int y = x + fuzz;
- return fuzz >= 0 ? (y >= x ? y : UINT_MAX) : (y <= x ? y : 0);
-}
-
-static unsigned int
-clamp(unsigned int x, unsigned int min, unsigned int max)
-{
- return x < min ? min : x > max ? max : x;
-}
-
-static unsigned int
-calc_t2(unsigned int lease)
-{
- unsigned int base = lease * 0.875;
- return lease >= 60 ? clamp(fuzz(base, 10), 0, lease - 1) : base;
-}
-
-static unsigned int
-calc_t1(unsigned int lease, unsigned int t2)
-{
- unsigned int base = lease / 2;
- return lease >= 60 ? clamp(fuzz(base, 10), 0, t2 - 1) : base;
-}
+++ /dev/null
-/*
- * Copyright (c) 2008, 2010 Nicira Networks.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef DHCP_CLIENT_H
-#define DHCP_CLIENT_H 1
-
-#include <stdbool.h>
-#include <stdint.h>
-
-struct dhclient;
-struct dhcp_msg;
-struct netdev;
-int dhclient_create(const char *netdev,
- void (*modify_request)(struct dhcp_msg *, void *aux),
- bool (*validate_offer)(const struct dhcp_msg *, void *aux),
- void *aux, struct dhclient **);
-void dhclient_set_max_timeout(struct dhclient *, unsigned int max_timeout);
-void dhclient_destroy(struct dhclient *);
-
-struct netdev *dhclient_get_netdev(struct dhclient *);
-const char *dhclient_get_name(const struct dhclient *);
-
-void dhclient_init(struct dhclient *, uint32_t requested_ip);
-void dhclient_release(struct dhclient *);
-void dhclient_force_renew(struct dhclient *, int deadline);
-bool dhclient_is_bound(const struct dhclient *);
-bool dhclient_changed(struct dhclient *);
-
-const char *dhclient_get_state(const struct dhclient *);
-unsigned int dhclient_get_state_elapsed(const struct dhclient *);
-unsigned int dhclient_get_lease_remaining(const struct dhclient *);
-
-uint32_t dhclient_get_ip(const struct dhclient *);
-uint32_t dhclient_get_netmask(const struct dhclient *);
-uint32_t dhclient_get_router(const struct dhclient *);
-const struct dhcp_msg *dhclient_get_config(const struct dhclient *);
-
-int dhclient_configure_netdev(struct dhclient *);
-int dhclient_update_resolv_conf(struct dhclient *);
-
-void dhclient_run(struct dhclient *);
-void dhclient_wait(struct dhclient *);
-
-#endif /* dhcp-client.h */
+++ /dev/null
-/*
- * Copyright (c) 2008, 2010 Nicira Networks.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <config.h>
-#include "dhcp.h"
-#include <arpa/inet.h>
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <stdlib.h>
-#include "dynamic-string.h"
-#include "ofpbuf.h"
-#include "vlog.h"
-
-VLOG_DEFINE_THIS_MODULE(dhcp);
-
-/* Information about a DHCP argument type. */
-struct arg_type {
- const char *name; /* Name. */
- size_t size; /* Number of bytes per argument. */
-};
-
-static struct arg_type types[] = {
-#define DHCP_ARG(NAME, SIZE) [DHCP_ARG_##NAME] = {#NAME, SIZE},
- DHCP_ARGS
-#undef DHCP_ARG
-};
-
-/* Information about a DHCP option. */
-struct option_class {
- const char *name; /* Name. */
- enum dhcp_arg_type type; /* Argument type. */
- size_t min_args; /* Minimum number of arguments. */
- size_t max_args; /* Maximum number of arguments. */
-};
-
-static const struct option_class *
-get_option_class(int code)
-{
- static struct option_class classes[DHCP_N_OPTIONS];
- static bool init = false;
- if (!init) {
- int i;
-
- init = true;
-#define DHCP_OPT(NAME, CODE, TYPE, MIN, MAX) \
- classes[CODE].name = #NAME; \
- classes[CODE].type = DHCP_ARG_##TYPE; \
- classes[CODE].min_args = MIN; \
- classes[CODE].max_args = MAX;
- DHCP_OPTS
-#undef DHCP_OPT
-
- for (i = 0; i < DHCP_N_OPTIONS; i++) {
- if (!classes[i].name) {
- classes[i].name = xasprintf("option-%d", i);
- classes[i].type = DHCP_ARG_UINT8;
- classes[i].min_args = 0;
- classes[i].max_args = SIZE_MAX;
- }
- }
- }
- assert(code >= 0 && code < DHCP_N_OPTIONS);
- return &classes[code];
-}
-
-/* A single (bad) DHCP message can in theory dump out many, many log messages,
- * especially at high logging levels, so the burst size is set quite high
- * here to avoid missing useful information. */
-struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 600);
-
-static void copy_data(struct dhcp_msg *);
-
-const char *
-dhcp_type_name(enum dhcp_msg_type type)
-{
- switch (type) {
-#define DHCP_MSG(NAME, VALUE) case NAME: return #NAME;
- DHCP_MSGS
-#undef DHCP_MSG
- }
- return "<<unknown DHCP message type>>";
-}
-
-/* Initializes 'msg' as a DHCP message. The message should be freed with
- * dhcp_msg_uninit() when it is no longer needed. */
-void
-dhcp_msg_init(struct dhcp_msg *msg)
-{
- memset(msg, 0, sizeof *msg);
-}
-
-/* Frees the contents of 'msg'. The caller is responsible for freeing 'msg',
- * if necessary. */
-void
-dhcp_msg_uninit(struct dhcp_msg *msg)
-{
- if (msg) {
- free(msg->data);
- }
-}
-
-/* Initializes 'dst' as a copy of 'src'. 'dst' (and 'src') should be freed
- * with dhcp_msg_uninit() when it is no longer needed. */
-void
-dhcp_msg_copy(struct dhcp_msg *dst, const struct dhcp_msg *src)
-{
- *dst = *src;
- dst->data_allocated = src->data_used;
- dst->data_used = 0;
- dst->data = xmalloc(dst->data_allocated);
- copy_data(dst);
-}
-
-static void
-prealloc_data(struct dhcp_msg *msg, size_t n)
-{
- size_t needed = msg->data_used + n;
- if (needed > msg->data_allocated) {
- uint8_t *old_data = msg->data;
- msg->data_allocated = MAX(needed * 2, 64);
- msg->data = xmalloc(msg->data_allocated);
- if (old_data) {
- copy_data(msg);
- free(old_data);
- }
- }
-}
-
-static void *
-append_data(struct dhcp_msg *msg, const void *data, size_t n)
-{
- uint8_t *p = &msg->data[msg->data_used];
- memcpy(p, data, n);
- msg->data_used += n;
- return p;
-}
-
-static void
-copy_data(struct dhcp_msg *msg)
-{
- int code;
-
- msg->data_used = 0;
- for (code = 0; code < DHCP_N_OPTIONS; code++) {
- struct dhcp_option *opt = &msg->options[code];
- if (opt->data) {
- assert(msg->data_used + opt->n <= msg->data_allocated);
- opt->data = append_data(msg, opt->data, opt->n);
- }
- }
-}
-
-/* Appends the 'n' bytes in 'data' to the DHCP option in 'msg' represented by
- * 'code' (which must be in the range 0...DHCP_N_OPTIONS). */
-void
-dhcp_msg_put(struct dhcp_msg *msg, int code,
- const void *data, size_t n)
-{
- struct dhcp_option *opt;
- if (code == DHCP_CODE_PAD || code == DHCP_CODE_END) {
- return;
- }
-
- opt = &msg->options[code];
- prealloc_data(msg, n + opt->n);
- if (opt->n) {
- if (&msg->data[msg->data_used - opt->n] != opt->data) {
- opt->data = append_data(msg, opt->data, opt->n);
- }
- append_data(msg, data, n);
- } else {
- opt->data = append_data(msg, data, n);
- }
- opt->n += n;
-}
-
-/* Appends the boolean value 'b', as a octet with value 0 (false) or 1 (true),
- * to the DHCP option in 'msg' represented by 'code' (which must be in the
- * range 0...DHCP_N_OPTIONS). */
-void
-dhcp_msg_put_bool(struct dhcp_msg *msg, int code, bool b_)
-{
- char b = !!b_;
- dhcp_msg_put(msg, code, &b, 1);
-}
-
-/* Appends the number of seconds 'secs', as a 32-bit number in network byte
- * order, to the DHCP option in 'msg' represented by 'code' (which must be in
- * the range 0...DHCP_N_OPTIONS). */
-void
-dhcp_msg_put_secs(struct dhcp_msg *msg, int code, uint32_t secs_)
-{
- uint32_t secs = htonl(secs_);
- dhcp_msg_put(msg, code, &secs, sizeof secs);
-}
-
-/* Appends the IP address 'ip', as a 32-bit number in network byte order, to
- * the DHCP option in 'msg' represented by 'code' (which must be in the range
- * 0...DHCP_N_OPTIONS). */
-void
-dhcp_msg_put_ip(struct dhcp_msg *msg, int code, uint32_t ip)
-{
- dhcp_msg_put(msg, code, &ip, sizeof ip);
-}
-
-/* Appends the ASCII string 'string', to the DHCP option in 'msg' represented
- * by 'code' (which must be in the range 0...DHCP_N_OPTIONS). */
-void
-dhcp_msg_put_string(struct dhcp_msg *msg, int code, const char *string)
-{
- dhcp_msg_put(msg, code, string, strlen(string));
-}
-
-/* Appends octet 'x' to DHCP option in 'msg' represented by 'code' (which must
- * be in the range 0...DHCP_N_OPTIONS). */
-void
-dhcp_msg_put_uint8(struct dhcp_msg *msg, int code, uint8_t x)
-{
- dhcp_msg_put(msg, code, &x, sizeof x);
-}
-
-/* Appends the 'n' octets in 'data' to DHCP option in 'msg' represented by
- * 'code' (which must be in the range 0...DHCP_N_OPTIONS). */
-void dhcp_msg_put_uint8_array(struct dhcp_msg *msg, int code,
- const uint8_t data[], size_t n)
-{
- dhcp_msg_put(msg, code, data, n);
-}
-
-/* Appends the 16-bit value in 'x', in network byte order, to DHCP option in
- * 'msg' represented by 'code' (which must be in the range
- * 0...DHCP_N_OPTIONS). */
-void
-dhcp_msg_put_uint16(struct dhcp_msg *msg, int code, uint16_t x_)
-{
- uint16_t x = htons(x_);
- dhcp_msg_put(msg, code, &x, sizeof x);
-}
-
-
-/* Appends the 'n' 16-bit values in 'data', in network byte order, to DHCP
- * option in 'msg' represented by 'code' (which must be in the range
- * 0...DHCP_N_OPTIONS). */
-void
-dhcp_msg_put_uint16_array(struct dhcp_msg *msg, int code,
- const uint16_t data[], size_t n)
-{
- size_t i;
-
- for (i = 0; i < n; i++) {
- dhcp_msg_put_uint16(msg, code, data[i]);
- }
-}
-
-/* Returns a pointer to the 'size' bytes starting at byte offset 'offset' in
- * the DHCP option in 'msg' represented by 'code' (which must be in the range
- * 0...DHCP_N_OPTIONS). If the option has fewer than 'offset + size' bytes,
- * returns a null pointer. */
-const void *
-dhcp_msg_get(const struct dhcp_msg *msg, int code,
- size_t offset, size_t size)
-{
- const struct dhcp_option *opt = &msg->options[code];
- return offset + size <= opt->n ? (const char *) opt->data + offset : NULL;
-}
-
-/* Stores in '*out' the boolean value at byte offset 'offset' in the DHCP
- * option in 'msg' represented by 'code' (which must be in the range
- * 0...DHCP_N_OPTIONS). Returns true if successful, false if the option has
- * fewer than 'offset + 1' bytes. */
-bool
-dhcp_msg_get_bool(const struct dhcp_msg *msg, int code, size_t offset,
- bool *out)
-{
- const uint8_t *uint8 = dhcp_msg_get(msg, code, offset, sizeof *uint8);
- if (uint8) {
- *out = *uint8 != 0;
- return true;
- } else {
- return false;
- }
-}
-
-/* Stores in '*out' the 32-bit count of seconds at offset 'offset' (in
- * 4-byte increments) in the DHCP option in 'msg' represented by 'code'
- * (which must be in the range 0...DHCP_N_OPTIONS). The value is converted to
- * native byte order. Returns true if successful, false if the option has
- * fewer than '4 * (offset + 1)' bytes. */
-bool
-dhcp_msg_get_secs(const struct dhcp_msg *msg, int code, size_t offset,
- uint32_t *out)
-{
- const uint32_t *uint32 = dhcp_msg_get(msg, code, offset * sizeof *uint32,
- sizeof *uint32);
- if (uint32) {
- *out = ntohl(*uint32);
- return true;
- } else {
- return false;
- }
-}
-
-/* Stores in '*out' the IP address at offset 'offset' (in 4-byte increments) in
- * the DHCP option in 'msg' represented by 'code' (which must be in the range
- * 0...DHCP_N_OPTIONS). The IP address is stored in network byte order.
- * Returns true if successful, false if the option has fewer than '4 * (offset
- * + 1)' bytes. */
-bool
-dhcp_msg_get_ip(const struct dhcp_msg *msg, int code,
- size_t offset, uint32_t *out)
-{
- const uint32_t *uint32 = dhcp_msg_get(msg, code, offset * sizeof *uint32,
- sizeof *uint32);
- if (uint32) {
- *out = *uint32;
- return true;
- } else {
- return false;
- }
-}
-
-/* Returns the string in the DHCP option in 'msg' represented by 'code' (which
- * must be in the range 0...DHCP_N_OPTIONS). The caller is responsible for
- * freeing the string with free().
- *
- * If 'msg' has no option represented by 'code', returns a null pointer. (If
- * the option was specified but had no content, then an empty string is
- * returned, not a null pointer.) */
-char *
-dhcp_msg_get_string(const struct dhcp_msg *msg, int code)
-{
- const struct dhcp_option *opt = &msg->options[code];
- return opt->data ? xmemdup0(opt->data, opt->n) : NULL;
-}
-
-/* Stores in '*out' the octet at byte offset 'offset' in the DHCP option in
- * 'msg' represented by 'code' (which must be in the range 0...DHCP_N_OPTIONS).
- * Returns true if successful, false if the option has fewer than 'offset + 1'
- * bytes. */
-bool
-dhcp_msg_get_uint8(const struct dhcp_msg *msg, int code,
- size_t offset, uint8_t *out)
-{
- const uint8_t *uint8 = dhcp_msg_get(msg, code, offset, sizeof *uint8);
- if (uint8) {
- *out = *uint8;
- return true;
- } else {
- return false;
- }
-}
-
-/* Stores in '*out' the 16-bit value at offset 'offset' (in 2-byte units) in
- * the DHCP option in 'msg' represented by 'code' (which must be in the range
- * 0...DHCP_N_OPTIONS). The value is converted to native byte order. Returns
- * true if successful, false if the option has fewer than '2 * (offset + 1)'
- * bytes. */
-bool
-dhcp_msg_get_uint16(const struct dhcp_msg *msg, int code,
- size_t offset, uint16_t *out)
-{
- const uint16_t *uint16 = dhcp_msg_get(msg, code, offset * sizeof *uint16,
- sizeof *uint16);
- if (uint16) {
- *out = ntohs(*uint16);
- return true;
- } else {
- return false;
- }
-}
-
-/* Appends a string representing 'duration' seconds to 'ds'. */
-static void
-put_duration(struct ds *ds, unsigned int duration)
-{
- if (duration) {
- if (duration >= 86400) {
- ds_put_format(ds, "%ud", duration / 86400);
- duration %= 86400;
- }
- if (duration >= 3600) {
- ds_put_format(ds, "%uh", duration / 3600);
- duration %= 3600;
- }
- if (duration >= 60) {
- ds_put_format(ds, "%umin", duration / 60);
- duration %= 60;
- }
- if (duration > 0) {
- ds_put_format(ds, "%us", duration);
- }
- } else {
- ds_put_cstr(ds, "0s");
- }
-}
-
-/* Appends a string representation of 'opt', which has the given 'code', to
- * 'ds'. */
-const char *
-dhcp_option_to_string(const struct dhcp_option *opt, int code, struct ds *ds)
-{
- const struct option_class *class = get_option_class(code);
- const struct arg_type *type = &types[class->type];
- size_t offset;
- const char *cp;
-
- for (cp = class->name; *cp; cp++) {
- unsigned char c = *cp;
- ds_put_char(ds, c == '_' ? '-' : tolower(c));
- }
- ds_put_char(ds, '=');
-
- if (!opt->data || !opt->n) {
- ds_put_cstr(ds, opt->data ? "empty" : "null");
- return ds_cstr(ds);
- }
-
- if (class->type == DHCP_ARG_STRING) {
- ds_put_char(ds, '"');
- ds_put_printable(ds, opt->data, opt->n);
- ds_put_char(ds, '"');
- return ds_cstr(ds);
- }
- for (offset = 0; offset + type->size <= opt->n; offset += type->size) {
- const void *p = (const char *) opt->data + offset;
- const uint8_t *uint8 = p;
- const uint32_t *uint32 = p;
- const uint16_t *uint16 = p;
-
- if (offset && class->type != DHCP_ARG_STRING) {
- ds_put_cstr(ds, class->type == DHCP_ARG_UINT8 ? ":" : ", ");
- }
- switch (class->type) {
- case DHCP_ARG_FIXED:
- NOT_REACHED();
- case DHCP_ARG_IP:
- ds_put_format(ds, IP_FMT, IP_ARGS(uint32));
- break;
- case DHCP_ARG_UINT8:
- ds_put_format(ds, "%02"PRIx8, *uint8);
- break;
- case DHCP_ARG_UINT16:
- ds_put_format(ds, "%"PRIu16, ntohs(*uint16));
- break;
- case DHCP_ARG_UINT32:
- ds_put_format(ds, "%"PRIu32, ntohl(*uint32));
- break;
- case DHCP_ARG_SECS:
- put_duration(ds, ntohl(*uint32));
- break;
- case DHCP_ARG_STRING:
- NOT_REACHED();
- case DHCP_ARG_BOOLEAN:
- if (*uint8 == 0) {
- ds_put_cstr(ds, "false");
- } else if (*uint8 == 1) {
- ds_put_cstr(ds, "true");
- } else {
- ds_put_format(ds, "**%"PRIu8"**", *uint8);
- }
- break;
- }
- }
- if (offset != opt->n) {
- if (offset) {
- ds_put_cstr(ds, ", ");
- }
- ds_put_cstr(ds, "**leftovers:");
- for (; offset < opt->n; offset++) {
- const void *p = (const char *) opt->data + offset;
- const uint8_t *uint8 = p;
- ds_put_format(ds, " %"PRIu8, *uint8);
- }
- ds_put_cstr(ds, "**");
- }
- return ds_cstr(ds);
-}
-
-/* Returns true if 'a' and 'b' have the same content, false otherwise. */
-bool
-dhcp_option_equals(const struct dhcp_option *a, const struct dhcp_option *b)
-{
- return ((a->data != NULL) == (b->data != NULL)
- && a->n == b->n
- && (!a->data || !memcmp(a->data, b->data, a->n)));
-}
-
-/* Replaces 'ds' by a string representation of 'msg'. If 'multiline' is
- * false, 'ds' receives a single-line representation of 'msg', otherwise a
- * multiline representation. */
-const char *
-dhcp_msg_to_string(const struct dhcp_msg *msg, bool multiline, struct ds *ds)
-{
- char separator = multiline ? '\n' : ' ';
- int code;
-
- ds_clear(ds);
- ds_put_format(ds, "op=%s",
- (msg->op == DHCP_BOOTREQUEST ? "request"
- : msg->op == DHCP_BOOTREPLY ? "reply"
- : "error"));
- ds_put_format(ds, "%ctype=%s", separator, dhcp_type_name(msg->type));
- ds_put_format(ds, "%cxid=0x%08"PRIx32, separator, msg->xid);
- ds_put_format(ds, "%csecs=", separator);
- put_duration(ds, msg->secs);
- if (msg->flags) {
- ds_put_format(ds, "%cflags=", separator);
- if (msg->flags & DHCP_FLAGS_BROADCAST) {
- ds_put_cstr(ds, "[BROADCAST]");
- }
- if (msg->flags & DHCP_FLAGS_MBZ) {
- ds_put_format(ds, "[0x%04"PRIx16"]", msg->flags & DHCP_FLAGS_MBZ);
- }
- }
- if (msg->ciaddr) {
- ds_put_format(ds, "%cciaddr="IP_FMT, separator, IP_ARGS(&msg->ciaddr));
- }
- if (msg->yiaddr) {
- ds_put_format(ds, "%cyiaddr="IP_FMT, separator, IP_ARGS(&msg->yiaddr));
- }
- if (msg->siaddr) {
- ds_put_format(ds, "%csiaddr="IP_FMT, separator, IP_ARGS(&msg->siaddr));
- }
- if (msg->giaddr) {
- ds_put_format(ds, "%cgiaddr="IP_FMT, separator, IP_ARGS(&msg->giaddr));
- }
- ds_put_format(ds, "%cchaddr="ETH_ADDR_FMT,
- separator, ETH_ADDR_ARGS(msg->chaddr));
-
- for (code = 0; code < DHCP_N_OPTIONS; code++) {
- const struct dhcp_option *opt = &msg->options[code];
- if (opt->data) {
- ds_put_char(ds, separator);
- dhcp_option_to_string(opt, code, ds);
- }
- }
- if (multiline) {
- ds_put_char(ds, separator);
- }
- return ds_cstr(ds);
-}
-
-static void
-parse_options(struct dhcp_msg *msg, const char *name, void *data, size_t size,
- int option_offset)
-{
- struct ofpbuf b;
-
- ofpbuf_use_const(&b, data, size);
- for (;;) {
- uint8_t *code, *len;
- void *payload;
-
- code = ofpbuf_try_pull(&b, 1);
- if (!code || *code == DHCP_CODE_END) {
- break;
- } else if (*code == DHCP_CODE_PAD) {
- continue;
- }
-
- len = ofpbuf_try_pull(&b, 1);
- if (!len) {
- VLOG_DBG_RL(&rl, "reached end of %s expecting length byte", name);
- break;
- }
-
- payload = ofpbuf_try_pull(&b, *len);
- if (!payload) {
- VLOG_DBG_RL(&rl, "expected %"PRIu8" bytes of option-%"PRIu8" "
- "payload with only %zu bytes of %s left",
- *len, *code, b.size, name);
- break;
- }
- dhcp_msg_put(msg, *code + option_offset, payload, *len);
- }
-}
-
-static void
-validate_options(struct dhcp_msg *msg)
-{
- int code;
-
- for (code = 0; code < DHCP_N_OPTIONS; code++) {
- struct dhcp_option *opt = &msg->options[code];
- const struct option_class *class = get_option_class(code);
- struct arg_type *type = &types[class->type];
- if (opt->data) {
- size_t n_elems = opt->n / type->size;
- size_t remainder = opt->n % type->size;
- bool ok = true;
- if (remainder) {
- VLOG_DBG_RL(&rl, "%s option has %zu %zu-byte %s arguments "
- "with %zu bytes left over",
- class->name, n_elems, type->size,
- type->name, remainder);
- ok = false;
- }
- if (n_elems < class->min_args || n_elems > class->max_args) {
- VLOG_DBG_RL(&rl, "%s option has %zu %zu-byte %s arguments but "
- "between %zu and %zu are required",
- class->name, n_elems, type->size, type->name,
- class->min_args, class->max_args);
- ok = false;
- }
- if (!ok) {
- struct ds ds = DS_EMPTY_INITIALIZER;
- VLOG_DBG_RL(&rl, "%s option contains: %s", class->name,
- dhcp_option_to_string(opt, code, &ds));
- ds_destroy(&ds);
-
- opt->n = 0;
- opt->data = NULL;
- }
- }
- }
-}
-
-/* Attempts to parse 'b' as a DHCP message. If successful, initializes '*msg'
- * to the parsed message and returns 0. Otherwise, returns a positive errno
- * value and '*msg' is indeterminate. */
-int
-dhcp_parse(struct dhcp_msg *msg, const struct ofpbuf *b_)
-{
- struct ofpbuf b = *b_;
- struct dhcp_header *dhcp;
- uint32_t *cookie;
- uint8_t type;
- char *vendor_class;
-
- dhcp = ofpbuf_try_pull(&b, sizeof *dhcp);
- if (!dhcp) {
- VLOG_DBG_RL(&rl, "buffer too small for DHCP header (%zu bytes)",
- b.size);
- goto error;
- }
-
- if (dhcp->op != DHCP_BOOTREPLY && dhcp->op != DHCP_BOOTREQUEST) {
- VLOG_DBG_RL(&rl, "invalid DHCP op (%"PRIu8")", dhcp->op);
- goto error;
- }
- if (dhcp->htype != ARP_HRD_ETHERNET) {
- VLOG_DBG_RL(&rl, "invalid DHCP htype (%"PRIu8")", dhcp->htype);
- goto error;
- }
- if (dhcp->hlen != ETH_ADDR_LEN) {
- VLOG_DBG_RL(&rl, "invalid DHCP hlen (%"PRIu8")", dhcp->hlen);
- goto error;
- }
-
- dhcp_msg_init(msg);
- msg->op = dhcp->op;
- msg->xid = ntohl(dhcp->xid);
- msg->secs = ntohs(dhcp->secs);
- msg->flags = ntohs(dhcp->flags);
- msg->ciaddr = dhcp->ciaddr;
- msg->yiaddr = dhcp->yiaddr;
- msg->siaddr = dhcp->siaddr;
- msg->giaddr = dhcp->giaddr;
- memcpy(msg->chaddr, dhcp->chaddr, ETH_ADDR_LEN);
-
- cookie = ofpbuf_try_pull(&b, sizeof *cookie);
- if (cookie) {
- if (ntohl(*cookie) == DHCP_OPTS_COOKIE) {
- uint8_t overload;
-
- parse_options(msg, "options", b.data, b.size, 0);
- if (dhcp_msg_get_uint8(msg, DHCP_CODE_OPTION_OVERLOAD,
- 0, &overload)) {
- if (overload & 1) {
- parse_options(msg, "file", dhcp->file, sizeof dhcp->file,
- 0);
- }
- if (overload & 2) {
- parse_options(msg, "sname",
- dhcp->sname, sizeof dhcp->sname, 0);
- }
- }
- } else {
- VLOG_DBG_RL(&rl, "bad DHCP options cookie: %08"PRIx32,
- ntohl(*cookie));
- }
- } else {
- VLOG_DBG_RL(&rl, "DHCP packet has no options");
- }
-
- vendor_class = dhcp_msg_get_string(msg, DHCP_CODE_VENDOR_CLASS);
- if (vendor_class && !strcmp(vendor_class, "OpenFlow")) {
- parse_options(msg, "vendor-specific",
- msg->options[DHCP_CODE_VENDOR_SPECIFIC].data,
- msg->options[DHCP_CODE_VENDOR_SPECIFIC].n,
- DHCP_VENDOR_OFS);
- }
- free(vendor_class);
-
- validate_options(msg);
- if (!dhcp_msg_get_uint8(msg, DHCP_CODE_DHCP_MSG_TYPE, 0, &type)) {
- VLOG_DBG_RL(&rl, "missing DHCP message type");
- dhcp_msg_uninit(msg);
- goto error;
- }
- msg->type = type;
- return 0;
-
-error:
- if (VLOG_IS_DBG_ENABLED()) {
- struct ds ds;
-
- ds_init(&ds);
- ds_put_hex_dump(&ds, b_->data, b_->size, 0, true);
- VLOG_DBG_RL(&rl, "invalid DHCP message dump:\n%s", ds_cstr(&ds));
-
- ds_clear(&ds);
- dhcp_msg_to_string(msg, false, &ds);
- VLOG_DBG_RL(&rl, "partially dissected DHCP message: %s", ds_cstr(&ds));
-
- ds_destroy(&ds);
- }
- return EPROTO;
-}
-
-static void
-put_option_chunk(struct ofpbuf *b, uint8_t code, void *data, size_t n)
-{
- uint8_t header[2];
-
- assert(n < 256);
- header[0] = code;
- header[1] = n;
- ofpbuf_put(b, header, sizeof header);
- ofpbuf_put(b, data, n);
-}
-
-static void
-put_option(struct ofpbuf *b, uint8_t code, void *data, size_t n)
-{
- if (data) {
- if (n) {
- /* Divide the data into chunks of 255 bytes or less. Make
- * intermediate chunks multiples of 8 bytes in case the
- * recipient validates a chunk at a time instead of the
- * concatenated value. */
- uint8_t *p = data;
- while (n) {
- size_t chunk = n > 255 ? 248 : n;
- put_option_chunk(b, code, p, chunk);
- p += chunk;
- n -= chunk;
- }
- } else {
- /* Option should be present but carry no data. */
- put_option_chunk(b, code, NULL, 0);
- }
- }
-}
-
-/* Appends to 'b' the DHCP message represented by 'msg'. */
-void
-dhcp_assemble(const struct dhcp_msg *msg, struct ofpbuf *b)
-{
- const uint8_t end = DHCP_CODE_END;
- uint32_t cookie = htonl(DHCP_OPTS_COOKIE);
- struct ofpbuf vnd_data;
- struct dhcp_header dhcp;
- int i;
-
- memset(&dhcp, 0, sizeof dhcp);
- dhcp.op = msg->op;
- dhcp.htype = ARP_HRD_ETHERNET;
- dhcp.hlen = ETH_ADDR_LEN;
- dhcp.hops = 0;
- dhcp.xid = htonl(msg->xid);
- dhcp.secs = htons(msg->secs);
- dhcp.flags = htons(msg->flags);
- dhcp.ciaddr = msg->ciaddr;
- dhcp.yiaddr = msg->yiaddr;
- dhcp.siaddr = msg->siaddr;
- dhcp.giaddr = msg->giaddr;
- memcpy(dhcp.chaddr, msg->chaddr, ETH_ADDR_LEN);
- ofpbuf_put(b, &dhcp, sizeof dhcp);
- ofpbuf_put(b, &cookie, sizeof cookie);
-
- /* Put DHCP message type first. (The ordering is not required but it
- * seems polite.) */
- if (msg->type) {
- uint8_t type = msg->type;
- put_option(b, DHCP_CODE_DHCP_MSG_TYPE, &type, 1);
- }
-
- /* Put the standard options. */
- for (i = 0; i < DHCP_VENDOR_OFS; i++) {
- const struct dhcp_option *option = &msg->options[i];
- put_option(b, i, option->data, option->n);
- }
-
- /* Assemble vendor specific option and put it. */
- ofpbuf_init(&vnd_data, 0);
- for (i = DHCP_VENDOR_OFS; i < DHCP_N_OPTIONS; i++) {
- const struct dhcp_option *option = &msg->options[i];
- put_option(&vnd_data, i - DHCP_VENDOR_OFS, option->data, option->n);
- }
- if (vnd_data.size) {
- put_option(b, DHCP_CODE_VENDOR_SPECIFIC, vnd_data.data, vnd_data.size);
- }
- ofpbuf_uninit(&vnd_data);
-
- /* Put end-of-options option. */
- ofpbuf_put(b, &end, sizeof end);
-}
-
/*
- * Copyright (c) 2008 Nicira Networks.
+ * Copyright (c) 2008, 2011 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include "packets.h"
#include "util.h"
-struct ds;
-struct ofpbuf;
-
/* Ports used by DHCP. */
#define DHCP_SERVER_PORT 67 /* Port used by DHCP server. */
#define DHCP_CLIENT_PORT 68 /* Port used by DHCP client. */
-/* Values for 'op' field. */
-#define DHCP_BOOTREQUEST 1 /* Message sent by DHCP client. */
-#define DHCP_BOOTREPLY 2 /* Message sent by DHCP server. */
-
-/* Bits in 'flags' field. */
-#define DHCP_FLAGS_BROADCAST 0x8000 /* Server must broadcast all replies. */
-#define DHCP_FLAGS_MBZ 0x7fff /* Must be zero. */
-
-/* First four bytes of 'options' field. */
-#define DHCP_OPTS_COOKIE 0x63825363
-
#define DHCP_HEADER_LEN 236
struct dhcp_header {
uint8_t op; /* DHCP_BOOTREQUEST or DHCP_BOOTREPLY. */
};
BUILD_ASSERT_DECL(DHCP_HEADER_LEN == sizeof(struct dhcp_header));
-#define DHCP_ARGS \
- DHCP_ARG(FIXED, 0) /* Fixed-length option (PAD and END only). */ \
- DHCP_ARG(IP, 4) /* IP addresses. */ \
- DHCP_ARG(SECS, 4) /* 32-bit duration in seconds. */ \
- DHCP_ARG(STRING, 1) /* NVT string, optionally null-terminated. */ \
- DHCP_ARG(UINT8, 1) /* 8-bit unsigned integer. */ \
- DHCP_ARG(UINT16, 2) /* 16-bit unsigned integer. */ \
- DHCP_ARG(UINT32, 4) /* 32-bit unsigned integer. */ \
- DHCP_ARG(BOOLEAN, 1) /* Boolean octet (0 or 1). */
-
-/* DHCP option argument types. */
-enum dhcp_arg_type {
-#define DHCP_ARG(NAME, SIZE) DHCP_ARG_##NAME,
- DHCP_ARGS
-#undef DHCP_ARG
-};
-
-#define DHCP_MSGS \
- DHCP_MSG(DHCPDISCOVER, 1) /* Client->server: What IPs are available? */ \
- DHCP_MSG(DHCPOFFER, 2) /* Server->client: This IP is available. */ \
- DHCP_MSG(DHCPREQUEST, 3) /* Client->server: I want that IP. */ \
- DHCP_MSG(DHCPDECLINE, 4) /* Client->server: That IP is in use!. */ \
- DHCP_MSG(DHCPACK, 5) /* Server->client: You can have that IP. */ \
- DHCP_MSG(DHCPNAK, 6) /* Server->client: You can't have that IP. */ \
- DHCP_MSG(DHCPRELEASE, 7) /* Client->server: I'm done with this IP. */ \
- DHCP_MSG(DCHPINFORM, 8) /* Client->server: I'm using this IP. */
-
-/* DHCP message type (this is the argument for the DHCP_MSG_TYPE option). */
-enum dhcp_msg_type {
-#define DHCP_MSG(NAME, VALUE) NAME = VALUE,
- DHCP_MSGS
-#undef DHCP_MSG
-};
-const char *dhcp_type_name(enum dhcp_msg_type);
-
-/* DHCP allows for 256 standardized options and 256 vendor-specific options.
- * We put them in a single array, with the standard options at the
- * beginning. */
-#define DHCP_N_OPTIONS 512
-#define DHCP_VENDOR_OFS 256
-
-/* DHCP options. */
-#define DHCP_OPTS \
- /* arg min max */ \
- /* name code type args args */ \
- DHCP_OPT(PAD, 0, FIXED, 0, 0) \
- DHCP_OPT(END, 255, FIXED, 0, 0) \
- DHCP_OPT(SUBNET_MASK, 1, IP, 1, 1) \
- DHCP_OPT(TIME_OFFSET, 2, SECS, 1, 1) \
- DHCP_OPT(ROUTER, 3, IP, 1, SIZE_MAX) \
- /* Time Server Option is obsolete. */ \
- /* Name Server Option is obsolete. */ \
- DHCP_OPT(DNS_SERVER, 6, IP, 1, SIZE_MAX) \
- /* Log Server Option is obsolete. */ \
- /* Cookie Server Option is obsolete. */ \
- DHCP_OPT(LPR_SERVER, 9, IP, 1, SIZE_MAX) \
- /* Impress Server Option is obsolete. */ \
- /* Resource Location Server Option is obsolete. */ \
- DHCP_OPT(HOST_NAME, 12, STRING, 1, SIZE_MAX) \
- DHCP_OPT(BOOT_FILE_SIZE, 13, UINT16, 1, 1) \
- /* Merit Dump File option is obsolete. */ \
- DHCP_OPT(DOMAIN_NAME, 15, STRING, 1, SIZE_MAX) \
- /* Swap Server option is obsolete. */ \
- DHCP_OPT(ROOT_PATH, 17, STRING, 1, SIZE_MAX) \
- DHCP_OPT(EXTENSIONS_PATH, 18, STRING, 1, SIZE_MAX) \
- DHCP_OPT(IP_FORWARDING, 19, BOOLEAN, 1, 1) \
- DHCP_OPT(SOURCE_ROUTING, 20, BOOLEAN, 1, 1) \
- DHCP_OPT(POLICY_FILTER, 21, IP, 2, SIZE_MAX) \
- DHCP_OPT(MAX_DGRAM_REASSEMBLY, 22, UINT16, 1, 1) \
- DHCP_OPT(IP_TTL, 23, UINT8, 1, 1) \
- DHCP_OPT(PATH_MTU_TIMEOUT, 24, SECS, 1, 1) \
- DHCP_OPT(PATH_MTU_PLATEAU, 25, UINT16, 2, SIZE_MAX) \
- DHCP_OPT(MTU, 26, UINT16, 1, 1) \
- DHCP_OPT(ALL_SUBNETS_ARE_LOCAL, 27, BOOLEAN, 1, 1) \
- DHCP_OPT(BROADCAST_ADDRESS, 28, IP, 1, 1) \
- DHCP_OPT(PERFORM_MASK_DISCOVERY, 29, BOOLEAN, 1, 1) \
- DHCP_OPT(MASK_SUPPLIER, 30, BOOLEAN, 1, 1) \
- DHCP_OPT(PERFORM_ROUTER_DISCOVERY, 31, BOOLEAN, 1, 1) \
- DHCP_OPT(ROUTER_SOLICITATION, 32, IP, 1, 1) \
- DHCP_OPT(STATIC_ROUTE, 33, IP, 2, SIZE_MAX) \
- /* Trailer Encapsulation Option is obsolete. */ \
- DHCP_OPT(ARP_CACHE_TIMEOUT, 35, SECS, 1, 1) \
- DHCP_OPT(ETHERNET_ENCAPSULATION, 36, BOOLEAN, 1, 1) \
- DHCP_OPT(TCP_TTL, 37, UINT8, 1, 1) \
- DHCP_OPT(TCP_KEEPALIVE_INTERVAL, 38, SECS, 1, 1) \
- DHCP_OPT(TCP_KEEPALIVE_GARBAGE, 39, BOOLEAN, 1, 1) \
- DHCP_OPT(NIS_DOMAIN, 40, STRING, 1, SIZE_MAX) \
- DHCP_OPT(NIS_SERVERS, 41, IP, 1, SIZE_MAX) \
- DHCP_OPT(NTP_SERVERS, 42, IP, 1, SIZE_MAX) \
- DHCP_OPT(VENDOR_SPECIFIC, 43, UINT8, 1, SIZE_MAX) \
- DHCP_OPT(NETBIOS_NS, 44, IP, 1, SIZE_MAX) \
- DHCP_OPT(NETBIOS_DDS, 45, IP, 1, SIZE_MAX) \
- DHCP_OPT(NETBIOS_NODE_TYPE, 46, UINT8, 1, 1) \
- DHCP_OPT(NETBIOS_SCOPE, 47, STRING, 1, SIZE_MAX) \
- DHCP_OPT(X_FONT_SERVER, 48, IP, 1, SIZE_MAX) \
- DHCP_OPT(XDM, 49, IP, 1, SIZE_MAX) \
- DHCP_OPT(NISPLUS_DOMAIN, 64, STRING, 1, SIZE_MAX) \
- DHCP_OPT(NISPLUS_SERVERS, 65, IP, 1, SIZE_MAX) \
- DHCP_OPT(MOBILE_IP_HOME_AGENT, 68, IP, 0, SIZE_MAX) \
- DHCP_OPT(SMTP_SERVER, 69, IP, 1, SIZE_MAX) \
- DHCP_OPT(POP3_SERVER, 70, IP, 1, SIZE_MAX) \
- DHCP_OPT(NNTP_SERVER, 71, IP, 1, SIZE_MAX) \
- DHCP_OPT(WWW_SERVER, 72, IP, 1, SIZE_MAX) \
- DHCP_OPT(FINGER_SERVER, 73, IP, 1, SIZE_MAX) \
- DHCP_OPT(IRC_SERVER, 74, IP, 1, SIZE_MAX) \
- /* StreetTalk Server Option is obsolete. */ \
- /* StreetTalk Directory Assistance Server Option is obsolete. */ \
- DHCP_OPT(REQUESTED_IP, 50, IP, 1, 1) \
- DHCP_OPT(LEASE_TIME, 51, SECS, 1, 1) \
- DHCP_OPT(OPTION_OVERLOAD, 52, UINT8, 1, 1) \
- DHCP_OPT(TFTP_SERVER, 66, STRING, 1, SIZE_MAX) \
- DHCP_OPT(BOOTFILE_NAME, 67, STRING, 1, SIZE_MAX) \
- DHCP_OPT(DHCP_MSG_TYPE, 53, UINT8, 1, 1) \
- DHCP_OPT(SERVER_IDENTIFIER, 54, IP, 1, 1) \
- DHCP_OPT(PARAMETER_REQUEST_LIST, 55, UINT8, 1, SIZE_MAX) \
- DHCP_OPT(MESSAGE, 56, STRING, 1, SIZE_MAX) \
- DHCP_OPT(MAX_DHCP_MSG_SIZE, 57, UINT16, 1, 1) \
- DHCP_OPT(T1, 58, SECS, 1, 1) \
- DHCP_OPT(T2, 59, SECS, 1, 1) \
- DHCP_OPT(VENDOR_CLASS, 60, STRING, 1, SIZE_MAX) \
- DHCP_OPT(CLIENT_ID, 61, UINT8, 2, SIZE_MAX) \
- DHCP_VNDOPT(OFP_CONTROLLER_VCONN, 1, STRING, 1, SIZE_MAX) \
- DHCP_VNDOPT(OFP_PKI_URI, 2, STRING, 1, SIZE_MAX)
-
-/* Shorthand for defining vendor options (used above). */
-#define DHCP_VNDOPT(NAME, CODE, ARG, MIN, MAX) \
- DHCP_OPT(NAME, (CODE) + DHCP_VENDOR_OFS, ARG, MIN, MAX)
-
-/* DHCP option codes. */
-enum {
-#define DHCP_OPT(NAME, VALUE, ARGTYPE, MIN_ARGS, MAX_ARGS) \
- DHCP_CODE_##NAME = VALUE,
-DHCP_OPTS
-#undef DHCP_OPT
-};
-
-/* The contents of a DHCP option.
- *
- * DHCP options can (rarely) be present but lack content. To represent such an
- * option, 'n' is 0 and 'data' is non-null (but does not point to anything
- * useful). */
-struct dhcp_option {
- size_t n; /* Number of bytes of data. */
- void *data; /* Data. */
-};
-
-const char *dhcp_option_to_string(const struct dhcp_option *, int code,
- struct ds *);
-bool dhcp_option_equals(const struct dhcp_option *,
- const struct dhcp_option *);
-
-/* Abstracted DHCP protocol message, to make them easier to manipulate than
- * through raw protocol buffers. */
-struct dhcp_msg {
- /* For use by calling code. */
- uint8_t op; /* DHCP_BOOTREQUEST or DHCP_BOOTREPLY. */
- uint32_t xid; /* Transaction ID. */
- uint16_t secs; /* Since client started address acquisition. */
- uint16_t flags; /* DHCP_FLAGS_*. */
- uint32_t ciaddr; /* Client IP, if it has a lease for one. */
- uint32_t yiaddr; /* Client ("your") IP address. */
- uint32_t siaddr; /* Next server IP address. */
- uint32_t giaddr; /* Relay agent IP address. */
- uint8_t chaddr[ETH_ADDR_LEN]; /* Client hardware address. */
- enum dhcp_msg_type type; /* DHCP_CODE_DHCP_MSG_TYPE option argument. */
- struct dhcp_option options[DHCP_N_OPTIONS]; /* Indexed by option code. */
-
- /* For direct use only by dhcp_msg_*() functions. */
- uint8_t *data;
- size_t data_used, data_allocated;
-};
-
-void dhcp_msg_init(struct dhcp_msg *);
-void dhcp_msg_uninit(struct dhcp_msg *);
-void dhcp_msg_copy(struct dhcp_msg *, const struct dhcp_msg *);
-void dhcp_msg_put(struct dhcp_msg *, int code, const void *, size_t);
-void dhcp_msg_put_bool(struct dhcp_msg *, int code, bool);
-void dhcp_msg_put_secs(struct dhcp_msg *, int code, uint32_t);
-void dhcp_msg_put_ip(struct dhcp_msg *, int code, uint32_t);
-void dhcp_msg_put_string(struct dhcp_msg *, int code, const char *);
-void dhcp_msg_put_uint8(struct dhcp_msg *, int code, uint8_t);
-void dhcp_msg_put_uint8_array(struct dhcp_msg *, int code,
- const uint8_t[], size_t n);
-void dhcp_msg_put_uint16(struct dhcp_msg *, int code, uint16_t);
-void dhcp_msg_put_uint16_array(struct dhcp_msg *, int code,
- const uint16_t[], size_t n);
-const void *dhcp_msg_get(const struct dhcp_msg *, int code, size_t offset,
- size_t size);
-bool dhcp_msg_get_bool(const struct dhcp_msg *, int code,
- size_t offset, bool *);
-bool dhcp_msg_get_secs(const struct dhcp_msg *, int code,
- size_t offset, uint32_t *);
-bool dhcp_msg_get_ip(const struct dhcp_msg *, int code,
- size_t offset, uint32_t *);
-char *dhcp_msg_get_string(const struct dhcp_msg *, int code);
-bool dhcp_msg_get_uint8(const struct dhcp_msg *, int code,
- size_t offset, uint8_t *);
-bool dhcp_msg_get_uint16(const struct dhcp_msg *, int code,
- size_t offset, uint16_t *);
-const char *dhcp_msg_to_string(const struct dhcp_msg *, bool multiline,
- struct ds *);
-int dhcp_parse(struct dhcp_msg *, const struct ofpbuf *);
-void dhcp_assemble(const struct dhcp_msg *, struct ofpbuf *);
-
#endif /* dhcp.h */
*
* May return -EOPNOTSUPP if a network device does not implement packet
* reception through this interface. This function may be set to null if
- * it would always return -EOPNOTSUPP anyhow. (This will disable the OVS
- * integrated DHCP client and OpenFlow controller discovery, and prevent
- * the network device from being usefully used by the netdev-based
- * "userspace datapath".) */
+ * it would always return -EOPNOTSUPP anyhow. (This will prevent the
+ * network device from being usefully used by the netdev-based "userspace
+ * datapath".) */
int (*recv)(struct netdev *netdev, void *buffer, size_t size);
/* Registers with the poll loop to wake up from the next call to
*
* May return EOPNOTSUPP if a network device does not implement packet
* transmission through this interface. This function may be set to null
- * if it would always return EOPNOTSUPP anyhow. (This will disable the OVS
- * integrated DHCP client and OpenFlow controller discovery, and prevent
- * the network device from being usefully used by the netdev-based
- * "userspace datapath".) */
+ * if it would always return EOPNOTSUPP anyhow. (This will prevent the
+ * network device from being usefully used by the netdev-based "userspace
+ * datapath".) */
int (*send)(struct netdev *netdev, const void *buffer, size_t size);
/* Registers with the poll loop to wake up from the next call to
time_t creation_time;
unsigned long int total_time_connected;
- /* If we can't connect to the peer, it could be for any number of reasons.
- * Usually, one would assume it is because the peer is not running or
- * because the network is partitioned. But it could also be because the
- * network topology has changed, in which case the upper layer will need to
- * reassess it (in particular, obtain a new IP address via DHCP and find
- * the new location of the controller). We set this flag when we suspect
- * that this could be the case. */
- bool questionable_connectivity;
- time_t last_questioned;
-
/* Throughout this file, "probe" is shorthand for "inactivity probe".
* When nothing has been received from the peer for a while, we send out
* an echo request as an inactivity probe packet. We should receive back
static void report_error(struct rconn *, int error);
static void disconnect(struct rconn *, int error);
static void flush_queue(struct rconn *);
-static void question_connectivity(struct rconn *);
static void copy_to_monitor(struct rconn *, const struct ofpbuf *);
static bool is_connected_state(enum state);
static bool is_admitted_msg(const struct ofpbuf *);
rc->creation_time = time_now();
rc->total_time_connected = 0;
- rc->questionable_connectivity = false;
- rc->last_questioned = time_now();
-
rconn_set_probe_interval(rc, probe_interval);
rc->n_monitors = 0;
run_IDLE(struct rconn *rc)
{
if (timed_out(rc)) {
- question_connectivity(rc);
VLOG_ERR("%s: no response to inactivity probe after %u "
"seconds, disconnecting",
rc->name, elapsed_in_this_state(rc));
return rconn->vconn ? vconn_get_local_port(rconn->vconn) : 0;
}
-/* If 'rconn' can't connect to the peer, it could be for any number of reasons.
- * Usually, one would assume it is because the peer is not running or because
- * the network is partitioned. But it could also be because the network
- * topology has changed, in which case the upper layer will need to reassess it
- * (in particular, obtain a new IP address via DHCP and find the new location
- * of the controller). When this appears that this might be the case, this
- * function returns true. It also clears the questionability flag and prevents
- * it from being set again for some time. */
-bool
-rconn_is_connectivity_questionable(struct rconn *rconn)
-{
- bool questionable = rconn->questionable_connectivity;
- rconn->questionable_connectivity = false;
- return questionable;
-}
-
/* Returns the total number of packets successfully received by the underlying
* vconn. */
unsigned int
}
rc->backoff_deadline = now + rc->backoff;
state_transition(rc, S_BACKOFF);
- if (now - rc->last_connected > 60) {
- question_connectivity(rc);
- }
} else {
rc->last_disconnected = time_now();
rconn_disconnect(rc);
rc->state_entered = time_now();
}
-static void
-question_connectivity(struct rconn *rc)
-{
- time_t now = time_now();
- if (now - rc->last_questioned > 60) {
- rc->questionable_connectivity = true;
- rc->last_questioned = now;
- }
-}
-
static void
copy_to_monitor(struct rconn *rc, const struct ofpbuf *b)
{
/*
- * Copyright (c) 2008, 2009, 2010 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
bool rconn_is_connected(const struct rconn *);
bool rconn_is_admitted(const struct rconn *);
int rconn_failure_duration(const struct rconn *);
-bool rconn_is_connectivity_questionable(struct rconn *);
uint32_t rconn_get_remote_ip(const struct rconn *);
uint16_t rconn_get_remote_port(const struct rconn *);
ofproto_libofproto_a_SOURCES = \
ofproto/collectors.c \
ofproto/collectors.h \
- ofproto/discovery.c \
- ofproto/discovery.h \
ofproto/fail-open.c \
ofproto/fail-open.h \
ofproto/in-band.c \
+++ /dev/null
-/*
- * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <config.h>
-#include "discovery.h"
-#include <errno.h>
-#include <inttypes.h>
-#include <sys/socket.h>
-#include <net/if.h>
-#include <regex.h>
-#include <stdlib.h>
-#include <string.h>
-#include "dhcp-client.h"
-#include "dhcp.h"
-#include "dpif.h"
-#include "netdev.h"
-#include "openflow/openflow.h"
-#include "packets.h"
-#include "stream-ssl.h"
-#include "vlog.h"
-
-VLOG_DEFINE_THIS_MODULE(discovery);
-
-struct discovery {
- char *dpif_name;
- char *re;
- bool update_resolv_conf;
- regex_t *regex;
- struct dhclient *dhcp;
- int n_changes;
-};
-
-static void modify_dhcp_request(struct dhcp_msg *, void *aux);
-static bool validate_dhcp_offer(const struct dhcp_msg *, void *aux);
-
-static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60);
-
-int
-discovery_create(const char *re, bool update_resolv_conf,
- struct dpif *dpif, struct discovery **discoveryp)
-{
- struct discovery *d;
- char local_name[IF_NAMESIZE];
- int error;
-
- d = xzalloc(sizeof *d);
-
- d->dpif_name = xstrdup(dpif_base_name(dpif));
-
- /* Controller regular expression. */
- error = discovery_set_accept_controller_re(d, re);
- if (error) {
- goto error_free;
- }
- d->update_resolv_conf = update_resolv_conf;
-
- /* Initialize DHCP client. */
- error = dpif_port_get_name(dpif, ODPP_LOCAL,
- local_name, sizeof local_name);
- if (error) {
- VLOG_ERR("%s: failed to query datapath local port: %s",
- d->dpif_name, strerror(error));
- goto error_regfree;
- }
- error = dhclient_create(local_name, modify_dhcp_request,
- validate_dhcp_offer, d, &d->dhcp);
- if (error) {
- VLOG_ERR("%s: failed to initialize DHCP client: %s",
- d->dpif_name, strerror(error));
- goto error_regfree;
- }
- dhclient_set_max_timeout(d->dhcp, 3);
- dhclient_init(d->dhcp, 0);
-
- *discoveryp = d;
- return 0;
-
-error_regfree:
- regfree(d->regex);
- free(d->regex);
-error_free:
- free(d->dpif_name);
- free(d);
- *discoveryp = 0;
- return error;
-}
-
-void
-discovery_destroy(struct discovery *d)
-{
- if (d) {
- free(d->re);
- regfree(d->regex);
- free(d->regex);
- dhclient_destroy(d->dhcp);
- free(d->dpif_name);
- free(d);
- }
-}
-
-bool
-discovery_get_update_resolv_conf(const struct discovery *d)
-{
- return d->update_resolv_conf;
-}
-
-void
-discovery_set_update_resolv_conf(struct discovery *d,
- bool update_resolv_conf)
-{
- d->update_resolv_conf = update_resolv_conf;
-}
-
-const char *
-discovery_get_accept_controller_re(const struct discovery *d)
-{
- return d->re;
-}
-
-int
-discovery_set_accept_controller_re(struct discovery *d, const char *re_)
-{
- regex_t *regex;
- int error;
- char *re;
-
- re = (!re_ ? xstrdup(stream_ssl_is_configured() ? "^ssl:.*" : "^tcp:.*")
- : re_[0] == '^' ? xstrdup(re_) : xasprintf("^%s", re_));
- regex = xmalloc(sizeof *regex);
- error = regcomp(regex, re, REG_NOSUB | REG_EXTENDED);
- if (error) {
- size_t length = regerror(error, regex, NULL, 0);
- char *buffer = xmalloc(length);
- regerror(error, regex, buffer, length);
- VLOG_WARN("%s: %s: %s", d->dpif_name, re, buffer);
- free(buffer);
- free(regex);
- free(re);
- return EINVAL;
- } else {
- if (d->regex) {
- regfree(d->regex);
- free(d->regex);
- }
- free(d->re);
-
- d->regex = regex;
- d->re = re;
- return 0;
- }
-}
-
-void
-discovery_question_connectivity(struct discovery *d)
-{
- if (d->dhcp) {
- dhclient_force_renew(d->dhcp, 15);
- }
-}
-
-bool
-discovery_run(struct discovery *d, char **controller_name)
-{
- if (!d->dhcp) {
- *controller_name = NULL;
- return true;
- }
-
- dhclient_run(d->dhcp);
- if (!dhclient_changed(d->dhcp)) {
- return false;
- }
-
- dhclient_configure_netdev(d->dhcp);
- if (d->update_resolv_conf) {
- dhclient_update_resolv_conf(d->dhcp);
- }
-
- if (dhclient_is_bound(d->dhcp)) {
- *controller_name = dhcp_msg_get_string(dhclient_get_config(d->dhcp),
- DHCP_CODE_OFP_CONTROLLER_VCONN);
- VLOG_INFO("%s: discovered controller %s",
- d->dpif_name, *controller_name);
- d->n_changes++;
- } else {
- *controller_name = NULL;
- if (d->n_changes) {
- VLOG_INFO("%s: discovered controller no longer available",
- d->dpif_name);
- d->n_changes++;
- }
- }
- return true;
-}
-
-void
-discovery_wait(struct discovery *d)
-{
- if (d->dhcp) {
- dhclient_wait(d->dhcp);
- }
-}
-
-static void
-modify_dhcp_request(struct dhcp_msg *msg, void *aux OVS_UNUSED)
-{
- dhcp_msg_put_string(msg, DHCP_CODE_VENDOR_CLASS, "OpenFlow");
-}
-
-static bool
-validate_dhcp_offer(const struct dhcp_msg *msg, void *d_)
-{
- const struct discovery *d = d_;
- char *vconn_name;
- bool accept;
-
- vconn_name = dhcp_msg_get_string(msg, DHCP_CODE_OFP_CONTROLLER_VCONN);
- if (!vconn_name) {
- VLOG_WARN_RL(&rl, "%s: rejecting DHCP offer missing controller vconn",
- d->dpif_name);
- return false;
- }
- accept = !regexec(d->regex, vconn_name, 0, NULL, 0);
- if (!accept) {
- VLOG_WARN_RL(&rl, "%s: rejecting controller vconn that fails to "
- "match %s", d->dpif_name, d->re);
- }
- free(vconn_name);
- return accept;
-}
+++ /dev/null
-/*
- * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef DISCOVERY_H
-#define DISCOVERY_H 1
-
-#include <stdbool.h>
-
-struct dpif;
-struct discovery;
-struct settings;
-
-int discovery_create(const char *accept_controller_re, bool update_resolv_conf,
- struct dpif *, struct discovery **);
-void discovery_destroy(struct discovery *);
-bool discovery_get_update_resolv_conf(const struct discovery *);
-void discovery_set_update_resolv_conf(struct discovery *,
- bool update_resolv_conf);
-const char *discovery_get_accept_controller_re(const struct discovery *);
-int discovery_set_accept_controller_re(struct discovery *, const char *re);
-void discovery_question_connectivity(struct discovery *);
-bool discovery_run(struct discovery *, char **controller_name);
-void discovery_wait(struct discovery *);
-
-#endif /* discovery.h */
#include "byte-order.h"
#include "classifier.h"
#include "coverage.h"
-#include "discovery.h"
#include "dpif.h"
#include "dynamic-string.h"
#include "fail-open.h"
/* type == OFCONN_PRIMARY only. */
enum nx_role role; /* Role. */
struct hmap_node hmap_node; /* In struct ofproto's "controllers" map. */
- struct discovery *discovery; /* Controller discovery object, if enabled. */
enum ofproto_band band; /* In-band or out-of-band? */
};
}
}
-static bool
-is_discovery_controller(const struct ofproto_controller *c)
-{
- return !strcmp(c->target, "discover");
-}
-
-static bool
-is_in_band_controller(const struct ofproto_controller *c)
-{
- return is_discovery_controller(c) || c->band == OFPROTO_IN_BAND;
-}
-
/* Creates a new controller in 'ofproto'. Some of the settings are initially
* drawn from 'c', but update_controller() needs to be called later to finish
* the new ofconn's configuration. */
static void
add_controller(struct ofproto *ofproto, const struct ofproto_controller *c)
{
- struct discovery *discovery;
+ char *name = ofconn_make_name(ofproto, c->target);
struct ofconn *ofconn;
- if (is_discovery_controller(c)) {
- int error = discovery_create(c->accept_re, c->update_resolv_conf,
- ofproto->dpif, &discovery);
- if (error) {
- return;
- }
- } else {
- discovery = NULL;
- }
-
ofconn = ofconn_create(ofproto, rconn_create(5, 8), OFCONN_PRIMARY);
ofconn->pktbuf = pktbuf_create();
ofconn->miss_send_len = OFP_DEFAULT_MISS_SEND_LEN;
- if (discovery) {
- ofconn->discovery = discovery;
- } else {
- char *name = ofconn_make_name(ofproto, c->target);
- rconn_connect(ofconn->rconn, c->target, name);
- free(name);
- }
+ rconn_connect(ofconn->rconn, c->target, name);
hmap_insert(&ofproto->controllers, &ofconn->hmap_node,
hash_string(c->target, 0));
+
+ free(name);
}
/* Reconfigures 'ofconn' to match 'c'. This function cannot update an ofconn's
- * target or turn discovery on or off (these are done by creating new ofconns
- * and deleting old ones), but it can update the rest of an ofconn's
- * settings. */
+ * target (this is done by creating new ofconns and deleting old ones), but it
+ * can update the rest of an ofconn's settings. */
static void
update_controller(struct ofconn *ofconn, const struct ofproto_controller *c)
{
int probe_interval;
- ofconn->band = (is_in_band_controller(c)
- ? OFPROTO_IN_BAND : OFPROTO_OUT_OF_BAND);
+ ofconn->band = c->band;
rconn_set_max_backoff(ofconn->rconn, c->max_backoff);
probe_interval = c->probe_interval ? MAX(c->probe_interval, 5) : 0;
rconn_set_probe_interval(ofconn->rconn, probe_interval);
- if (ofconn->discovery) {
- discovery_set_update_resolv_conf(ofconn->discovery,
- c->update_resolv_conf);
- discovery_set_accept_controller_re(ofconn->discovery, c->accept_re);
- }
-
ofconn_set_rate_limit(ofconn, c->rate_limit, c->burst_limit);
}
static const char *
ofconn_get_target(const struct ofconn *ofconn)
{
- return ofconn->discovery ? "discover" : rconn_get_target(ofconn->rconn);
+ return rconn_get_target(ofconn->rconn);
}
static struct ofconn *
const struct ofconn *ofconn;
struct sockaddr_in *addrs;
size_t max_addrs, n_addrs;
- bool discovery;
size_t i;
/* Allocate enough memory for as many remotes as we could possibly have. */
n_addrs = 0;
/* Add all the remotes. */
- discovery = false;
HMAP_FOR_EACH (ofconn, hmap_node, &ofproto->controllers) {
struct sockaddr_in *sin = &addrs[n_addrs];
sin->sin_port = rconn_get_remote_port(ofconn->rconn);
n_addrs++;
}
- if (ofconn->discovery) {
- discovery = true;
- }
}
for (i = 0; i < ofproto->n_extra_remotes; i++) {
addrs[n_addrs++] = ofproto->extra_in_band_remotes[i];
}
- /* Create or update or destroy in-band.
- *
- * Ordinarily we only enable in-band if there's at least one remote
- * address, but discovery needs the in-band rules for DHCP to be installed
- * even before we know any remote addresses. */
- if (n_addrs || discovery) {
+ /* Create or update or destroy in-band. */
+ if (n_addrs) {
if (!ofproto->in_band) {
in_band_create(ofproto, ofproto->dpif, &ofproto->in_band);
}
for (i = 0; i < n_controllers; i++) {
const struct ofproto_controller *c = &controllers[i];
- if (!vconn_verify_name(c->target) || !strcmp(c->target, "discover")) {
+ if (!vconn_verify_name(c->target)) {
if (!find_controller_by_target(p, c->target)) {
add_controller(p, c);
}
if (ofconn->type == OFCONN_PRIMARY) {
hmap_remove(&ofconn->ofproto->controllers, &ofconn->hmap_node);
}
- discovery_destroy(ofconn->discovery);
list_remove(&ofconn->node);
rconn_destroy(ofconn->rconn);
int iteration;
size_t i;
- if (ofconn->discovery) {
- char *controller_name;
- if (rconn_is_connectivity_questionable(ofconn->rconn)) {
- discovery_question_connectivity(ofconn->discovery);
- }
- if (discovery_run(ofconn->discovery, &controller_name)) {
- if (controller_name) {
- char *ofconn_name = ofconn_make_name(p, controller_name);
- rconn_connect(ofconn->rconn, controller_name, ofconn_name);
- free(ofconn_name);
- free(controller_name);
- } else {
- rconn_disconnect(ofconn->rconn);
- }
- }
- }
-
for (i = 0; i < N_SCHEDULERS; i++) {
pinsched_run(ofconn->schedulers[i], do_send_packet_in, ofconn);
}
}
}
- if (!ofconn->discovery && !rconn_is_alive(ofconn->rconn)) {
+ if (!rconn_is_alive(ofconn->rconn)) {
ofconn_destroy(ofconn);
}
}
{
int i;
- if (ofconn->discovery) {
- discovery_wait(ofconn->discovery);
- }
for (i = 0; i < N_SCHEDULERS; i++) {
pinsched_wait(ofconn->schedulers[i]);
}
/*
- * Copyright (c) 2009, 2010 Nicira Networks.
+ * Copyright (c) 2009, 2010, 2011 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
int probe_interval; /* Max idle time before probing, in seconds. */
enum ofproto_band band; /* In-band or out-of-band? */
- /* Discovery options. */
- char *accept_re; /* Regexp for acceptable controllers. */
- bool update_resolv_conf; /* Update /etc/resolv.conf? */
-
/* OpenFlow packet-in rate-limiting. */
int rate_limit; /* Max packet-in rate in packets per second. */
int burst_limit; /* Limit on accumulating packet credits. */
/test-byte-order
/test-classifier
/test-csum
-/test-dhcp-client
/test-file_name
/test-flows
/test-hash
tests/lcov/test-byte-order \
tests/lcov/test-classifier \
tests/lcov/test-csum \
- tests/lcov/test-dhcp-client \
tests/lcov/test-file_name \
tests/lcov/test-flows \
tests/lcov/test-hash \
tests/valgrind/test-byte-order \
tests/valgrind/test-classifier \
tests/valgrind/test-csum \
- tests/valgrind/test-dhcp-client \
tests/valgrind/test-file_name \
tests/valgrind/test-flows \
tests/valgrind/test-hash \
noinst_PROGRAMS += tests/test-type-props
tests_test_type_props_SOURCES = tests/test-type-props.c
-noinst_PROGRAMS += tests/test-dhcp-client
-tests_test_dhcp_client_SOURCES = tests/test-dhcp-client.c
-tests_test_dhcp_client_LDADD = lib/libopenvswitch.a
-
noinst_PROGRAMS += tests/test-uuid
tests_test_uuid_SOURCES = tests/test-uuid.c
tests_test_uuid_LDADD = lib/libopenvswitch.a
+++ /dev/null
-/*
- * Copyright (c) 2008, 2009, 2010 Nicira Networks.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <config.h>
-#include "dhcp-client.h"
-#include <arpa/inet.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include <limits.h>
-#include "command-line.h"
-#include "dhcp.h"
-#include "fatal-signal.h"
-#include "poll-loop.h"
-#include "util.h"
-#include "vlog.h"
-
-/* --request-ip: IP address to request from server. If zero, then do not
- * request a specific IP address. */
-static struct in_addr request_ip;
-
-/* --vendor-class: Vendor class string to include in request. If null, no
- * vendor class string is included. */
-static const char *vendor_class;
-
-/* --no-resolv-conf: Update /etc/resolv.conf to match DHCP reply? */
-static bool update_resolv_conf = true;
-
-static void parse_options(int argc, char *argv[]);
-static void usage(void);
-static void release(void *cli_);
-static void modify_dhcp_request(struct dhcp_msg *, void *aux);
-
-int
-main(int argc, char *argv[])
-{
- struct dhclient *cli;
- int error;
-
- set_program_name(argv[0]);
- parse_options(argc, argv);
-
- argc -= optind;
- argv += optind;
- if (argc != 1) {
- ovs_fatal(0, "exactly one non-option argument required; "
- "use --help for help");
- }
-
- error = dhclient_create(argv[0], modify_dhcp_request, NULL, NULL, &cli);
- if (error) {
- ovs_fatal(error, "dhclient_create failed");
- }
- dhclient_init(cli, request_ip.s_addr);
- fatal_signal_add_hook(release, NULL, cli, true);
-
- for (;;) {
- dhclient_run(cli);
- if (dhclient_changed(cli)) {
- dhclient_configure_netdev(cli);
- if (update_resolv_conf) {
- dhclient_update_resolv_conf(cli);
- }
- }
- dhclient_wait(cli);
- poll_block();
- }
-}
-
-static void
-release(void *cli_)
-{
- struct dhclient *cli = cli_;
- dhclient_release(cli);
- if (dhclient_changed(cli)) {
- dhclient_configure_netdev(cli);
- }
-}
-
-static void
-modify_dhcp_request(struct dhcp_msg *msg, void *aux OVS_UNUSED)
-{
- if (vendor_class) {
- dhcp_msg_put_string(msg, DHCP_CODE_VENDOR_CLASS, vendor_class);
- }
-}
-
-static void
-parse_options(int argc, char *argv[])
-{
- enum {
- OPT_REQUEST_IP = UCHAR_MAX + 1,
- OPT_VENDOR_CLASS,
- OPT_NO_RESOLV_CONF
- };
- static struct option long_options[] = {
- {"request-ip", required_argument, 0, OPT_REQUEST_IP },
- {"vendor-class", required_argument, 0, OPT_VENDOR_CLASS },
- {"no-resolv-conf", no_argument, 0, OPT_NO_RESOLV_CONF},
- {"verbose", optional_argument, 0, 'v'},
- {"help", no_argument, 0, 'h'},
- {"version", no_argument, 0, 'V'},
- {0, 0, 0, 0},
- };
- char *short_options = long_options_to_short_options(long_options);
-
- for (;;) {
- int c;
-
- c = getopt_long(argc, argv, short_options, long_options, NULL);
- if (c == -1) {
- break;
- }
-
- switch (c) {
- case OPT_REQUEST_IP:
- if (!inet_aton(optarg, &request_ip)) {
- ovs_fatal(0,
- "--request-ip argument is not a valid IP address");
- }
- break;
-
- case OPT_VENDOR_CLASS:
- vendor_class = optarg;
- break;
-
- case OPT_NO_RESOLV_CONF:
- update_resolv_conf = false;
- break;
-
- case 'h':
- usage();
-
- case 'V':
- printf("%s %s compiled "__DATE__" "__TIME__"\n",
- program_name, VERSION BUILDNR);
- exit(EXIT_SUCCESS);
-
- case 'v':
- vlog_set_verbosity(optarg);
- break;
-
- case '?':
- exit(EXIT_FAILURE);
-
- default:
- abort();
- }
- }
- free(short_options);
-}
-
-static void
-usage(void)
-{
- printf("%s: standalone program for testing Open vSwitch DHCP client.\n"
- "usage: %s [OPTIONS] NETDEV\n"
- "where NETDEV is a network device (e.g. eth0).\n"
- "\nDHCP options:\n"
- " --request-ip=IP request specified IP address (default:\n"
- " do not request a specific IP)\n"
- " --vendor-class=STRING use STRING as vendor class; use\n"
- " OpenFlow to imitate ovs-openflowd\n"
- " --no-resolv-conf do not update /etc/resolv.conf\n",
- program_name, program_name);
- vlog_usage();
- printf("\nOther options:\n"
- " -h, --help display this help message\n"
- " -V, --version display version information\n");
- exit(EXIT_SUCCESS);
-}
-
/ovs-cfg-mod.8
/ovs-controller
/ovs-controller.8
-/ovs-discover
-/ovs-discover.8
/ovs-dpctl
/ovs-dpctl.8
/ovs-ofctl
bin_PROGRAMS += \
utilities/ovs-appctl \
utilities/ovs-controller \
- utilities/ovs-discover \
utilities/ovs-dpctl \
utilities/ovs-ofctl \
utilities/ovs-openflowd \
EXTRA_DIST += \
utilities/ovs-appctl.8.in \
utilities/ovs-controller.8.in \
- utilities/ovs-discover.8.in \
utilities/ovs-dpctl.8.in \
utilities/ovs-ofctl.8.in \
utilities/ovs-openflowd.8.in \
DISTCLEANFILES += \
utilities/ovs-appctl.8 \
utilities/ovs-controller.8 \
- utilities/ovs-discover.8 \
utilities/ovs-dpctl.8 \
utilities/ovs-ofctl.8 \
utilities/ovs-openflowd.8 \
man_MANS += \
utilities/ovs-appctl.8 \
utilities/ovs-controller.8 \
- utilities/ovs-discover.8 \
utilities/ovs-dpctl.8 \
utilities/ovs-ofctl.8 \
utilities/ovs-openflowd.8 \
utilities_ovs_controller_SOURCES = utilities/ovs-controller.c
utilities_ovs_controller_LDADD = lib/libopenvswitch.a $(SSL_LIBS)
-utilities_ovs_discover_SOURCES = utilities/ovs-discover.c
-utilities_ovs_discover_LDADD = lib/libopenvswitch.a
-
utilities_ovs_dpctl_SOURCES = utilities/ovs-dpctl.c
utilities_ovs_dpctl_LDADD = lib/libopenvswitch.a
.BR ovs\-vswitchd (8),
.BR ovs\-openflowd (8),
.BR ovs\-controller (8),
-.BR ovs\-brcompatd (8),
-.BR ovs\-discover (8).
+.BR ovs\-brcompatd (8).
+++ /dev/null
-.TH ovs\-discover 8 "May 2008" "Open vSwitch" "Open vSwitch Manual"
-.ds PN ovs\-discover
-
-.SH NAME
-ovs\-discover \- controller discovery utility
-
-.SH SYNOPSIS
-.B ovs\-discover
-[\fIoptions\fR] \fInetdev\fR [\fInetdev\fR...]
-
-.SH DESCRIPTION
-The \fBovs\-discover\fR program attempts to discover the location of
-an OpenFlow controller on one of the network devices listed on the
-command line. It repeatedly broadcasts a DHCP request with vendor
-class identifier \fBOpenFlow\fR on each network device until it
-receives an acceptable DHCP response. It will accept any valid DHCP
-reply that has the same vendor class identifier and includes a
-vendor-specific option with code 1 whose contents are a string
-specifying the location of the controller in the same format used on
-the \fBovs\-openflowd\fR command line (e.g. \fBssl:192.168.0.1\fR).
-
-When \fBovs\-discover\fR receives an acceptable response, it prints
-the details of the response on \fBstdout\fR. Then, by default, it
-configures the network device on which the response was received with
-the received IP address, netmask, and default gateway, and detaches
-itself to the background.
-
-.SH OPTIONS
-.TP
-\fB\-\-accept\-vconn=\fIregex\fR
-With this option, only controllers whose names match POSIX extended
-regular expression \fIregex\fR will be accepted. Specifying
-\fBssl:.*\fR for \fIregex\fR, for example, would cause only SSL
-controller connections to be accepted.
-
-The \fIregex\fR is implicitly anchored at the beginning of the
-controller location string, as if it begins with \fB^\fR.
-
-When this option is not given, the default \fIregex\fR is
-\fBtcp:.*\fR.
-.TP
-\fB\-\-exit\-without\-bind\fR
-By default, \fBovs\-discover\fR binds the network device that receives
-the first acceptable response to the IP address received over DHCP.
-With this option, the configuration of the network device is not
-changed at all, except to bring it up if it is initially down, and
-\fBovs\-discover\fR will exit immediately after it receives an
-acceptable DHCP response.
-
-This option is mutually exclusive with \fB\-\-exit\-after\-bind\fR and
-\fB\-\-no\-detach\fR.
-
-.TP
-\fB\-\-exit\-after\-bind\fR
-By default, after it receives an acceptable DHCP response,
-\fBovs\-discover\fR detaches itself from the foreground session and
-runs in the background maintaining the DHCP lease as necessary. With
-this option, \fBovs\-discover\fR will exit immediately after it
-receives an acceptable DHCP response and configures the network device
-with the received IP address. The address obtained via DHCP could
-therefore be used past the expiration of its lease.
-
-This option is mutually exclusive with \fB\-\-exit\-without\-bind\fR and
-\fB\-\-no\-detach\fR.
-
-.TP
-\fB\-\-no\-detach\fR
-By default, \fBovs\-discover\fR runs in the foreground until it obtains
-an acceptable DHCP response, then it detaches itself from the
-foreground session and run as a background process. This option
-prevents \fBovs\-discover\fR from detaching, causing it to run in the
-foreground even after it obtains a DHCP response.
-
-This option is mutually exclusive with \fB\-\-exit\-without\-bind\fR and
-\fB\-\-exit\-after\-bind\fR.
-
-.TP
-\fB\-\-pidfile\fR[\fB=\fIpidfile\fR]
-Causes a file (by default, \fBovs\-discover.pid\fR) to be created indicating
-the PID of the running process. If \fIpidfile\fR is not specified, or
-if it does not begin with \fB/\fR, then it is created in
-\fB@RUNDIR@\fR.
-
-The \fIpidfile\fR is created when \fBovs\-discover\fR detaches, so
-this this option has no effect when one of \fB\-\-exit\-without\-bind\fR,
-\fB\-\-exit\-after\-bind\fR, or \fB\-\-no\-detach\fR is also given.
-
-.TP
-\fB\-\-overwrite\-pidfile\fR
-By default, when \fB\-\-pidfile\fR is specified and the specified pidfile
-already exists and is locked by a running process, \fBcontroller\fR refuses
-to start. Specify \fB\-\-overwrite\-pidfile\fR to cause it to instead
-overwrite the pidfile.
-
-When \fB\-\-pidfile\fR is not specified, this option has no effect.
-
-.so lib/vlog.man
-.so lib/common.man
-
-.SH BUGS
-
-If the network devices specified on the command line have been added
-to an Open vSwitch datapath with \fBovs\-dpctl add\-if\fR, then controller
-discovery will fail because \fBovs\-discover\fR will not be able to
-see DHCP responses, even though tools such as \fBtcpdump\fR(8) and
-\fBwireshark\fR(1) can see them on the wire. This is because of the
-structure of the Linux kernel networking stack, which hands packets
-first to programs that listen for all arriving packets, then to
-Open vSwitch, then to programs that listen for a specific kind of packet.
-Open vSwitch consumes all the packets handed to it, so tools like
-\fBtcpdump\fR that look at all packets will see packets arriving on
-Open vSwitch interfaces, but \fRovs\-discover\fR, which listens only for
-arriving IP packets, will not.
-
-.SH "SEE ALSO"
-
-.BR ovs\-openflowd (8),
-.BR ovs\-pki (8)
+++ /dev/null
-/*
- * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <config.h>
-#include <getopt.h>
-#include <limits.h>
-#include <regex.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "command-line.h"
-#include "daemon.h"
-#include "dhcp-client.h"
-#include "dhcp.h"
-#include "dirs.h"
-#include "dynamic-string.h"
-#include "fatal-signal.h"
-#include "netdev.h"
-#include "poll-loop.h"
-#include "timeval.h"
-#include "unixctl.h"
-#include "util.h"
-#include "vlog.h"
-
-VLOG_DEFINE_THIS_MODULE(ovs_discover);
-
-struct iface {
- const char *name;
- struct dhclient *dhcp;
-};
-
-/* The interfaces that we serve. */
-static struct iface *ifaces;
-static int n_ifaces;
-
-/* --accept-vconn: Regular expression specifying the class of controller vconns
- * that we will accept during autodiscovery. */
-static const char *accept_controller_re = "tcp:.*";
-static regex_t accept_controller_regex;
-
-/* --exit-without-bind: Exit after discovering the controller, without binding
- * the network device to an IP address? */
-static bool exit_without_bind;
-
-/* --exit-after-bind: Exit after discovering the controller, after binding the
- * network device to an IP address? */
-static bool exit_after_bind;
-
-static bool iface_init(struct iface *, const char *netdev_name);
-static void release_ifaces(void *aux OVS_UNUSED);
-
-static void parse_options(int argc, char *argv[]);
-static void usage(void) NO_RETURN;
-
-static void modify_dhcp_request(struct dhcp_msg *, void *aux);
-static bool validate_dhcp_offer(const struct dhcp_msg *, void *aux);
-
-int
-main(int argc, char *argv[])
-{
- struct unixctl_server *unixctl;
- int retval;
- int i;
-
- proctitle_init(argc, argv);
- set_program_name(argv[0]);
- parse_options(argc, argv);
-
- argc -= optind;
- argv += optind;
- if (argc < 1) {
- ovs_fatal(0, "need at least one non-option argument; "
- "use --help for usage");
- }
-
- ifaces = xmalloc(argc * sizeof *ifaces);
- n_ifaces = 0;
- for (i = 0; i < argc; i++) {
- if (iface_init(&ifaces[n_ifaces], argv[i])) {
- n_ifaces++;
- }
- }
- if (!n_ifaces) {
- ovs_fatal(0, "failed to initialize any DHCP clients");
- }
-
- for (i = 0; i < n_ifaces; i++) {
- struct iface *iface = &ifaces[i];
- dhclient_init(iface->dhcp, 0);
- }
- fatal_signal_add_hook(release_ifaces, NULL, NULL, true);
-
- retval = regcomp(&accept_controller_regex, accept_controller_re,
- REG_NOSUB | REG_EXTENDED);
- if (retval) {
- size_t length = regerror(retval, &accept_controller_regex, NULL, 0);
- char *buffer = xmalloc(length);
- regerror(retval, &accept_controller_regex, buffer, length);
- ovs_fatal(0, "%s: %s", accept_controller_re, buffer);
- }
-
- retval = unixctl_server_create(NULL, &unixctl);
- if (retval) {
- exit(EXIT_FAILURE);
- }
-
- die_if_already_running();
-
- signal(SIGPIPE, SIG_IGN);
- for (;;) {
- for (i = 0; i < n_ifaces; i++) {
- struct iface *iface = &ifaces[i];
- dhclient_run(iface->dhcp);
- if (dhclient_changed(iface->dhcp)) {
- bool is_bound = dhclient_is_bound(iface->dhcp);
- int j;
-
- /* Configure network device. */
- if (!exit_without_bind) {
- dhclient_configure_netdev(iface->dhcp);
- dhclient_update_resolv_conf(iface->dhcp);
- }
-
- if (is_bound) {
- static bool detached = false;
- struct ds ds;
-
- /* Disable timeout, since discovery was successful. */
- time_alarm(0);
-
- /* Print discovered parameters. */
- ds_init(&ds);
- dhcp_msg_to_string(dhclient_get_config(iface->dhcp),
- true, &ds);
- fputs(ds_cstr(&ds), stdout);
- putchar('\n');
- fflush(stdout);
- ds_destroy(&ds);
-
- /* Exit if the user requested it. */
- if (exit_without_bind) {
- VLOG_DBG("exiting because of successful binding on %s "
- "and --exit-without-bind specified",
- iface->name);
- exit(0);
- }
- if (exit_after_bind) {
- VLOG_DBG("exiting because of successful binding on %s "
- "and --exit-after-bind specified",
- iface->name);
- exit(0);
- }
-
- /* Detach into background, if we haven't already. */
- if (!detached) {
- detached = true;
- daemonize();
- }
- }
-
- /* We only want an address on a single one of our interfaces.
- * So: if we have an address on this interface, stop looking
- * for one on the others; if we don't have an address on this
- * interface, start looking everywhere. */
- for (j = 0; j < n_ifaces; j++) {
- struct iface *if2 = &ifaces[j];
- if (iface != if2) {
- if (is_bound) {
- dhclient_release(if2->dhcp);
- } else {
- dhclient_init(if2->dhcp, 0);
- }
- }
- }
- }
- }
- unixctl_server_run(unixctl);
- for (i = 0; i < n_ifaces; i++) {
- struct iface *iface = &ifaces[i];
- dhclient_wait(iface->dhcp);
- }
- unixctl_server_wait(unixctl);
- poll_block();
- }
-
- return 0;
-}
-
-static bool
-iface_init(struct iface *iface, const char *netdev_name)
-{
- int retval;
-
- iface->name = netdev_name;
- iface->dhcp = NULL;
-
- if (exit_after_bind) {
- /* Bring this interface up permanently, so that the bound address
- * persists past program termination. */
- struct netdev *netdev;
-
- retval = netdev_open_default(iface->name, &netdev);
- if (retval) {
- ovs_error(retval, "Could not open %s device", iface->name);
- return false;
- }
- retval = netdev_turn_flags_on(netdev, NETDEV_UP, true);
- if (retval) {
- ovs_error(retval, "Could not bring %s device up", iface->name);
- return false;
- }
- netdev_close(netdev);
- }
-
- retval = dhclient_create(iface->name, modify_dhcp_request,
- validate_dhcp_offer, NULL, &iface->dhcp);
- if (retval) {
- ovs_error(retval, "%s: failed to initialize DHCP client", iface->name);
- return false;
- }
-
- return true;
-}
-
-static void
-release_ifaces(void *aux OVS_UNUSED)
-{
- int i;
-
- for (i = 0; i < n_ifaces; i++) {
- struct dhclient *dhcp = ifaces[i].dhcp;
- dhclient_release(dhcp);
- if (dhclient_changed(dhcp)) {
- dhclient_configure_netdev(dhcp);
- }
- }
-}
-
-static void
-modify_dhcp_request(struct dhcp_msg *msg, void *aux OVS_UNUSED)
-{
- dhcp_msg_put_string(msg, DHCP_CODE_VENDOR_CLASS, "OpenFlow");
-}
-
-static bool
-validate_dhcp_offer(const struct dhcp_msg *msg, void *aux OVS_UNUSED)
-{
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60);
- char *vconn_name;
- bool accept;
-
- vconn_name = dhcp_msg_get_string(msg, DHCP_CODE_OFP_CONTROLLER_VCONN);
- if (!vconn_name) {
- VLOG_WARN_RL(&rl, "rejecting DHCP offer missing controller vconn");
- return false;
- }
- accept = !regexec(&accept_controller_regex, vconn_name, 0, NULL, 0);
- free(vconn_name);
- return accept;
-}
-
-static void
-parse_options(int argc, char *argv[])
-{
- enum {
- OPT_ACCEPT_VCONN = UCHAR_MAX + 1,
- OPT_EXIT_WITHOUT_BIND,
- OPT_EXIT_AFTER_BIND,
- OPT_NO_DETACH,
- VLOG_OPTION_ENUMS,
- DAEMON_OPTION_ENUMS
- };
- static struct option long_options[] = {
- {"accept-vconn", required_argument, 0, OPT_ACCEPT_VCONN},
- {"exit-without-bind", no_argument, 0, OPT_EXIT_WITHOUT_BIND},
- {"exit-after-bind", no_argument, 0, OPT_EXIT_AFTER_BIND},
- {"no-detach", no_argument, 0, OPT_NO_DETACH},
- {"timeout", required_argument, 0, 't'},
- {"pidfile", optional_argument, 0, OPT_PIDFILE},
- {"overwrite-pidfile", no_argument, 0, OPT_OVERWRITE_PIDFILE},
- {"help", no_argument, 0, 'h'},
- {"version", no_argument, 0, 'V'},
- VLOG_LONG_OPTIONS,
- {0, 0, 0, 0},
- };
- char *short_options = long_options_to_short_options(long_options);
- bool detach_after_bind = true;
-
- for (;;) {
- unsigned long int timeout;
- int c;
-
- c = getopt_long(argc, argv, short_options, long_options, NULL);
- if (c == -1) {
- break;
- }
-
- switch (c) {
- case OPT_ACCEPT_VCONN:
- accept_controller_re = (optarg[0] == '^'
- ? optarg
- : xasprintf("^%s", optarg));
- break;
-
- case OPT_EXIT_WITHOUT_BIND:
- exit_without_bind = true;
- break;
-
- case OPT_EXIT_AFTER_BIND:
- exit_after_bind = true;
- break;
-
- case OPT_NO_DETACH:
- detach_after_bind = false;
- break;
-
- case OPT_PIDFILE:
- set_pidfile(optarg);
- break;
-
- case OPT_OVERWRITE_PIDFILE:
- ignore_existing_pidfile();
- break;
-
- case 't':
- timeout = strtoul(optarg, NULL, 10);
- if (timeout <= 0) {
- ovs_fatal(0, "value %s on -t or --timeout is not at least 1",
- optarg);
- } else {
- time_alarm(timeout);
- }
- signal(SIGALRM, SIG_DFL);
- break;
-
- case 'h':
- usage();
-
- case 'V':
- OVS_PRINT_VERSION(0, 0);
- exit(EXIT_SUCCESS);
-
- VLOG_OPTION_HANDLERS
-
- case '?':
- exit(EXIT_FAILURE);
-
- default:
- abort();
- }
- }
- free(short_options);
-
- if ((exit_without_bind + exit_after_bind + !detach_after_bind) > 1) {
- ovs_fatal(0, "--exit-without-bind, --exit-after-bind, and --no-detach "
- "are mutually exclusive");
- }
- if (detach_after_bind) {
- set_detach();
- }
-}
-
-static void
-usage(void)
-{
- printf("%s: a tool for discovering OpenFlow controllers.\n"
- "usage: %s [OPTIONS] NETDEV [NETDEV...]\n"
- "where each NETDEV is a network device on which to perform\n"
- "controller discovery.\n"
- "\nOrdinarily, ovs-discover runs in the foreground until it\n"
- "obtains an IP address and discovers an OpenFlow controller via\n"
- "DHCP, then it prints information about the controller to stdout\n"
- "and detaches to the background to maintain the IP address lease.\n"
- "\nNetworking options:\n"
- " --accept-vconn=REGEX accept matching discovered controllers\n"
- " --exit-without-bind exit after discovery, without binding\n"
- " --exit-after-bind exit after discovery, after binding\n"
- " --no-detach do not detach after discovery\n",
- program_name, program_name);
- vlog_usage();
- printf("\nOther options:\n"
- " -t, --timeout=SECS give up discovery after SECS seconds\n"
- " --pidfile[=FILE] create pidfile (default: %s/%s.pid)\n"
- " --overwrite-pidfile with --pidfile, start even if already "
- "running\n"
- " -h, --help display this help message\n"
- " -V, --version display version information\n",
- ovs_rundir(), program_name);
- exit(EXIT_SUCCESS);
-}
.
.SH SYNOPSIS
.B ovs\-openflowd
-[\fIoptions\fR] \fIdatapath\fR [\fIcontroller\fR\&...]
+[\fIoptions\fR] \fIdatapath\fR \fIcontroller\fR\&...
.
.SH DESCRIPTION
The \fBovs\-openflowd\fR program implements an OpenFlow switch using a
controllers are themselves designed to coordinate with each other.
(The Nicira-defined \fBNXT_ROLE\fR OpenFlow vendor extension may be
useful for this.)
-.PP
-If no \fIcontroller\fR is specified, \fBovs\-openflowd\fR attempts to
-discover the location of a controller automatically (see below).
.
.SS "Contacting Controllers"
The OpenFlow switch must be able to contact the OpenFlow controllers
.IP
In-band control is the default for \fBovs\-openflowd\fR, so no special
command-line option is required.
-.IP
-With in-band control, the location of the controller can be configured
-manually or discovered automatically:
-.
-.RS
-.IP "controller discovery"
-To make \fBovs\-openflowd\fR discover the location of the controller
-automatically, do not specify a controller on the \fBovs\-openflowd\fR
-command line.
-.IP
-In this mode, \fBovs\-openflowd\fR will broadcast a DHCP request with vendor
-class identifier \fBOpenFlow\fR across the network devices added to
-the datapath with \fBovs\-dpctl add\-if\fR. It will accept any valid DHCP
-reply that has the same vendor class identifier and includes a
-vendor-specific option with code 1 whose contents are a string
-specifying the location of the controller in the same format used on
-the \fBovs\-openflowd\fR command line (e.g. \fBssl:192.168.0.1\fR).
-.IP
-The DHCP reply may also, optionally, include a vendor-specific option
-with code 2 whose contents are a string specifying the URI to the base
-of the OpenFlow PKI (e.g. \fBhttp://192.168.0.1/openflow/pki\fR).
-This URI is used only for bootstrapping the OpenFlow PKI at initial
-switch setup; \fBovs\-openflowd\fR does not use it at all.
-.IP
-The following ISC DHCP server configuration file assigns the IP
-address range 192.168.0.20 through 192.168.0.30 to OpenFlow switches
-that follow the switch protocol and addresses 192.168.0.1 through
-192.168.0.10 to all other DHCP clients:
-.IP
-default\-lease\-time 600;
-.br
-max\-lease\-time 7200;
-.br
-option space openflow;
-.br
-option openflow.controller\-vconn code 1 = text;
-.br
-option openflow.pki\-uri code 2 = text;
-.br
-class "OpenFlow" {
-.br
- match if option vendor\-class\-identifier = "OpenFlow";
-.br
- vendor\-option\-space openflow;
-.br
- option openflow.controller\-vconn "tcp:192.168.0.10";
-.br
- option openflow.pki\-uri "http://192.168.0.10/openflow/pki";
-.br
- option vendor\-class\-identifier "OpenFlow";
-.br
-}
-.br
-subnet 192.168.0.0 netmask 255.255.255.0 {
-.br
- pool {
-.br
- allow members of "OpenFlow";
-.br
- range 192.168.0.20 192.168.0.30;
-.br
- }
-.br
- pool {
-.br
- deny members of "OpenFlow";
-.br
- range 192.168.0.1 192.168.0.10;
-.br
- }
-.br
-}
-.br
-.
-.IP "manual configuration"
-To configure in-band control manually, specify the location of the
+
+Specify the location of the
controller on the \fBovs\-openflowd\fR command line as the \fIcontroller\fR
argument. You must also configure the network device for the OpenFlow
``local port'' to allow \fBovs\-openflowd\fR to connect to that controller.
purposes and is not guaranteed to be unique and should not be used as
the primary identifier of the datapath.
.
-.SS "Controller Discovery Options"
-.TP
-\fB\-\-accept\-vconn=\fIregex\fR
-When \fBovs\-openflowd\fR performs controller discovery (see \fBContacting
-the Controller\fR, above, for more information about controller
-discovery), it validates the controller location obtained via DHCP
-with a POSIX extended regular expression. Only controllers whose
-names match the regular expression will be accepted.
-.IP
-The default regular expression is \fBssl:.*\fR (meaning that only SSL
-controller connections will be accepted) when any of the SSL
-configuration options \fB\-\-private\-key\fR, \fB\-\-certificate\fR, or
-\fB\-\-ca\-cert\fR is specified. The default is \fB^tcp:.*\fR otherwise
-(meaning that only TCP controller connections will be accepted).
-.IP
-The \fIregex\fR is implicitly anchored at the beginning of the
-controller location string, as if it begins with \fB^\fR.
-.IP
-When controller discovery is not performed, this option has no effect.
-.
-.TP
-\fB\-\-no\-resolv\-conf\fR
-When \fBovs\-openflowd\fR performs controller discovery (see \fBContacting
-the Controller\fR, above, for more information about controller
-discovery), by default it overwrites the system's
-\fB/etc/resolv.conf\fR with domain information and DNS servers
-obtained via DHCP. If the location of the controller is specified
-using a hostname, rather than an IP address, and the network's DNS
-servers ever change, this behavior is essential. But because it also
-interferes with any administrator or process that manages
-\fB/etc/resolv.conf\fR, when this option is specified, \fBovs\-openflowd\fR
-will not modify \fB/etc/resolv.conf\fR.
-.IP
-\fBovs\-openflowd\fR will only modify \fBresolv.conf\fR if the DHCP response
-that it receives specifies one or more DNS servers.
-.IP
-When controller discovery is not performed, this option has no effect.
-.
.SS "Networking Options"
.TP
\fB\-\-datapath\-id=\fIdpid\fR
.
.BR ovs\-appctl (8),
.BR ovs\-controller (8),
-.BR ovs\-discover (8),
.BR ovs\-dpctl (8),
.BR ovs\-ofctl (8),
.BR ovs\-pki (8)
OPT_SW_DESC,
OPT_SERIAL_DESC,
OPT_DP_DESC,
- OPT_ACCEPT_VCONN,
- OPT_NO_RESOLV_CONF,
OPT_BR_NAME,
OPT_FAIL_MODE,
OPT_INACTIVITY_PROBE,
{"sw-desc", required_argument, 0, OPT_SW_DESC},
{"serial-desc", required_argument, 0, OPT_SERIAL_DESC},
{"dp-desc", required_argument, 0, OPT_DP_DESC},
- {"accept-vconn", required_argument, 0, OPT_ACCEPT_VCONN},
- {"no-resolv-conf", no_argument, 0, OPT_NO_RESOLV_CONF},
{"config", required_argument, 0, 'F'},
{"br-name", required_argument, 0, OPT_BR_NAME},
{"fail", required_argument, 0, OPT_FAIL_MODE},
controller_opts.max_backoff = 8;
controller_opts.probe_interval = 5;
controller_opts.band = OFPROTO_IN_BAND;
- controller_opts.accept_re = NULL;
- controller_opts.update_resolv_conf = true;
controller_opts.rate_limit = 0;
controller_opts.burst_limit = 0;
s->unixctl_path = NULL;
s->dp_desc = optarg;
break;
- case OPT_ACCEPT_VCONN:
- controller_opts.accept_re = optarg;
- break;
-
- case OPT_NO_RESOLV_CONF:
- controller_opts.update_resolv_conf = false;
- break;
-
case OPT_FAIL_MODE:
if (!strcmp(optarg, "open") || !strcmp(optarg, "standalone")) {
s->fail_mode = OFPROTO_FAIL_STANDALONE;
argc -= optind;
argv += optind;
- if (argc < 1) {
- ovs_fatal(0, "need at least one non-option arguments; "
+ if (argc < 2) {
+ ovs_fatal(0, "need at least two non-option arguments; "
"use --help for usage");
}
- /* Set accept_controller_regex. */
- if (!controller_opts.accept_re) {
- controller_opts.accept_re
- = stream_ssl_is_configured() ? "^ssl:.*" : "^tcp:.*";
- }
-
/* Rate limiting. */
if (controller_opts.rate_limit && controller_opts.rate_limit < 100) {
VLOG_WARN("Rate limit set to unusually low value %d",
svec_add(&controllers, argv[i]);
}
}
- if (argc < 2) {
- svec_add(&controllers, "discover");
- }
/* Set up controllers. */
s->n_controllers = controllers.n;
s->controllers[i] = controller_opts;
s->controllers[i].target = controllers.names[i];
}
-
- /* Sanity check. */
- if (controller_opts.band == OFPROTO_OUT_OF_BAND) {
- for (i = 0; i < s->n_controllers; i++) {
- if (!strcmp(s->controllers[i].target, "discover")) {
- ovs_fatal(0, "Cannot perform discovery with out-of-band "
- "control");
- }
- }
- }
}
static void
usage(void)
{
printf("%s: an OpenFlow switch implementation.\n"
- "usage: %s [OPTIONS] [TYPE@]DATAPATH [CONTROLLER...]\n"
+ "usage: %s [OPTIONS] [TYPE@]DATAPATH CONTROLLER...\n"
"where DATAPATH is a local datapath (e.g. \"dp0\")\n"
"optionally with an explicit TYPE (default: \"system\").\n"
- "Each CONTROLLER is an active OpenFlow connection method. If\n"
- "none is given, ovs-openflowd performs controller discovery.\n",
+ "Each CONTROLLER is an active OpenFlow connection method.\n",
program_name, program_name);
vconn_usage(true, true, true);
printf("\nOpenFlow options:\n"
" --sw-desc=SW Identify software as SW\n"
" --serial-desc=SERIAL Identify serial number as SERIAL\n"
" --dp-desc=DP_DESC Identify dp description as DP_DESC\n"
- "\nController discovery options:\n"
- " --accept-vconn=REGEX accept matching discovered controllers\n"
- " --no-resolv-conf do not update /etc/resolv.conf\n"
"\nNetworking options:\n"
" --fail=open|closed when controller connection fails:\n"
" closed: drop all packets\n"
oc->max_backoff = 0;
oc->probe_interval = 60;
oc->band = OFPROTO_OUT_OF_BAND;
- oc->accept_re = NULL;
- oc->update_resolv_conf = false;
oc->rate_limit = 0;
oc->burst_limit = 0;
}
oc->probe_interval = c->inactivity_probe ? *c->inactivity_probe / 1000 : 5;
oc->band = (!c->connection_mode || !strcmp(c->connection_mode, "in-band")
? OFPROTO_IN_BAND : OFPROTO_OUT_OF_BAND);
- oc->accept_re = c->discover_accept_regex;
- oc->update_resolv_conf = c->discover_update_resolv_conf;
oc->rate_limit = c->controller_rate_limit ? *c->controller_rate_limit : 0;
oc->burst_limit = (c->controller_burst_limit
? *c->controller_burst_limit : 0);
struct iface *local_iface;
struct in_addr ip;
- /* Controller discovery does its own TCP/IP configuration later. */
- if (strcmp(c->target, "discover")) {
- return;
- }
-
/* If there's no local interface or no IP address, give up. */
local_iface = bridge_get_local_iface(br);
if (!local_iface || !c->local_ip || !inet_aton(c->local_ip, &ip)) {
{"name": "Open_vSwitch",
- "version": "2.1.0",
- "cksum": "1990266641 15714",
+ "version": "3.0.0",
+ "cksum": "705848946 15525",
"tables": {
"Open_vSwitch": {
"columns": {
"min": 0, "max": 1}},
"inactivity_probe": {
"type": {"key": "integer", "min": 0, "max": 1}},
- "discover_accept_regex": {
- "type": {"key": "string", "min": 0, "max": 1}},
- "discover_update_resolv_conf": {
- "type": {"key": "boolean", "min": 0, "max": 1}},
"connection_mode": {
"type": {"key": {"type": "string",
"enum": ["set", ["in-band", "out-of-band"]]},
<dd>The specified TCP <var>port</var> (default: 6633) on the host at
the given <var>ip</var>, which must be expressed as an IP address
(not a DNS name).</dd>
- <dt><code>discover</code></dt>
- <dd>
- <p>Enables controller discovery.</p>
- <p>In controller discovery mode, Open vSwitch broadcasts a DHCP
- request with vendor class identifier <code>OpenFlow</code> across
- all of the bridge's network devices. It will accept any valid
- DHCP reply that has the same vendor class identifier and includes
- a vendor-specific option with code 1 whose contents are a string
- specifying the location of the controller in the same format as
- <ref column="target"/>.</p>
- <p>The DHCP reply may also, optionally, include a vendor-specific
- option with code 2 whose contents are a string specifying the URI
- to the base of the OpenFlow PKI
- (e.g. <code>http://192.168.0.1/openflow/pki</code>). This URI is
- used only for bootstrapping the OpenFlow PKI at initial switch
- setup; <code>ovs-vswitchd</code> does not use it at all.</p>
- </dd>
</dl>
<p>
The following connection methods are currently supported for service
</dd>
</dl>
- <p>If not specified, the default is implementation-specific. If
- <ref column="target"/> is <code>discover</code>, the connection mode
- is always treated as <code>in-band</code> regardless of the actual
- setting.</p>
+ <p>If not specified, the default is implementation-specific.</p>
</column>
</group>
</column>
</group>
- <group title="Additional Discovery Configuration">
- <p>These values are considered only when <ref column="target"/>
- is <code>discover</code>.</p>
-
- <column name="discover_accept_regex">
- A POSIX
- extended regular expression against which the discovered controller
- location is validated. The regular expression is implicitly
- anchored at the beginning of the controller location string, as
- if it begins with <code>^</code>. If not specified, the default
- is implementation-specific.
- </column>
-
- <column name="discover_update_resolv_conf">
- Whether to update <code>/etc/resolv.conf</code> when the
- controller is discovered. If not specified, the default
- is implementation-specific. Open vSwitch will only modify
- <code>/etc/resolv.conf</code> if the DHCP response that it receives
- specifies one or more DNS servers.
- </column>
- </group>
-
<group title="Additional In-Band Configuration">
<p>These values are considered only in in-band control mode (see
- <ref column="connection_mode"/>) and only when <ref column="target"/>
- is not <code>discover</code>. (For controller discovery, the network
- configuration obtained via DHCP is used instead.)</p>
+ <ref column="connection_mode"/>).</p>
<p>When multiple controllers are configured on a single bridge, there
should be only one set of unique values in these columns. If different
# Get rid of stuff we don't want to make RPM happy.
rm \
$RPM_BUILD_ROOT/usr/bin/ovs-controller \
- $RPM_BUILD_ROOT/usr/bin/ovs-discover \
$RPM_BUILD_ROOT/usr/bin/ovs-openflowd \
$RPM_BUILD_ROOT/usr/bin/ovs-pki \
$RPM_BUILD_ROOT/usr/share/man/man8/ovs-controller.8 \
- $RPM_BUILD_ROOT/usr/share/man/man8/ovs-discover.8 \
$RPM_BUILD_ROOT/usr/share/man/man8/ovs-openflowd.8 \
$RPM_BUILD_ROOT/usr/share/man/man8/ovs-pki.8