summaryrefslogtreecommitdiffstats
path: root/sbin
diff options
context:
space:
mode:
authorglebius <glebius@FreeBSD.org>2011-12-16 12:16:56 +0000
committerglebius <glebius@FreeBSD.org>2011-12-16 12:16:56 +0000
commit27a36f6ac8242750daa092abd7180b10d16f4508 (patch)
tree059f66a20d251fa947969ff34292206d47ffc45c /sbin
parentb646d3f6998d3f539bcda6f94be4926461780cf7 (diff)
downloadFreeBSD-src-27a36f6ac8242750daa092abd7180b10d16f4508.zip
FreeBSD-src-27a36f6ac8242750daa092abd7180b10d16f4508.tar.gz
A major overhaul of the CARP implementation. The ip_carp.c was started
from scratch, copying needed functionality from the old implemenation on demand, with a thorough review of all code. The main change is that interface layer has been removed from the CARP. Now redundant addresses are configured exactly on the interfaces, they run on. The CARP configuration itself is, as before, configured and read via SIOCSVH/SIOCGVH ioctls. A new prefix created with SIOCAIFADDR or SIOCAIFADDR_IN6 may now be configured to a particular virtual host id, which makes the prefix redundant. ifconfig(8) semantics has been changed too: now one doesn't need to clone carpXX interface, he/she should directly configure a vhid on a Ethernet interface. To supply vhid data from the kernel to an application the getifaddrs(8) function had been changed to pass ifam_data with each address. [1] The new implementation definitely closes all PRs related to carp(4) being an interface, and may close several others. It also allows to run a single redundant IP per interface. Big thanks to Bjoern Zeeb for his help with inet6 part of patch, for idea on using ifam_data and for several rounds of reviewing! PR: kern/117000, kern/126945, kern/126714, kern/120130, kern/117448 Reviewed by: bz Submitted by: bz [1]
Diffstat (limited to 'sbin')
-rw-r--r--sbin/ifconfig/af_inet.c5
-rw-r--r--sbin/ifconfig/af_inet6.c2
-rw-r--r--sbin/ifconfig/ifcarp.c182
-rw-r--r--sbin/ifconfig/ifconfig.846
-rw-r--r--sbin/ifconfig/ifconfig.c15
-rw-r--r--sbin/ifconfig/ifconfig.h3
6 files changed, 164 insertions, 89 deletions
diff --git a/sbin/ifconfig/af_inet.c b/sbin/ifconfig/af_inet.c
index edb9b80..bcd17c4 100644
--- a/sbin/ifconfig/af_inet.c
+++ b/sbin/ifconfig/af_inet.c
@@ -84,8 +84,11 @@ in_status(int s __unused, const struct ifaddrs *ifa)
if (ifa->ifa_flags & IFF_BROADCAST) {
sin = (struct sockaddr_in *)ifa->ifa_broadaddr;
if (sin != NULL && sin->sin_addr.s_addr != 0)
- printf("broadcast %s", inet_ntoa(sin->sin_addr));
+ printf("broadcast %s ", inet_ntoa(sin->sin_addr));
}
+
+ print_vhid(ifa, " ");
+
putchar('\n');
}
diff --git a/sbin/ifconfig/af_inet6.c b/sbin/ifconfig/af_inet6.c
index e39c1c8..0731238 100644
--- a/sbin/ifconfig/af_inet6.c
+++ b/sbin/ifconfig/af_inet6.c
@@ -307,6 +307,8 @@ in6_status(int s __unused, const struct ifaddrs *ifa)
printf("infty ");
}
+ print_vhid(ifa, " ");
+
putchar('\n');
}
diff --git a/sbin/ifconfig/ifcarp.c b/sbin/ifconfig/ifcarp.c
index 2306717..2c58fcb 100644
--- a/sbin/ifconfig/ifcarp.c
+++ b/sbin/ifconfig/ifcarp.c
@@ -35,10 +35,11 @@
#include <stdlib.h>
#include <unistd.h>
-#include <net/ethernet.h>
#include <net/if.h>
+#include <net/if_var.h>
+#include <netinet/in.h>
+#include <netinet/in_var.h>
#include <netinet/ip_carp.h>
-#include <net/route.h>
#include <ctype.h>
#include <stdio.h>
@@ -52,127 +53,153 @@
static const char *carp_states[] = { CARP_STATES };
-void carp_status(int s);
-void setcarp_advbase(const char *,int, int, const struct afswtch *rafp);
-void setcarp_advskew(const char *, int, int, const struct afswtch *rafp);
-void setcarp_passwd(const char *, int, int, const struct afswtch *rafp);
-void setcarp_vhid(const char *, int, int, const struct afswtch *rafp);
+static void carp_status(int s);
+static void setcarp_vhid(const char *, int, int, const struct afswtch *rafp);
+static void setcarp_callback(int, void *);
+static void setcarp_advbase(const char *,int, int, const struct afswtch *rafp);
+static void setcarp_advskew(const char *, int, int, const struct afswtch *rafp);
+static void setcarp_passwd(const char *, int, int, const struct afswtch *rafp);
-void
+static int carpr_vhid = -1;
+static int carpr_advskew = -1;
+static int carpr_advbase = -1;
+static int carpr_state = -1;
+static unsigned char const *carpr_key;
+
+static void
carp_status(int s)
{
- const char *state;
- struct carpreq carpr;
+ struct carpreq carpr[CARP_MAXVHID];
+ int i;
- memset((char *)&carpr, 0, sizeof(struct carpreq));
+ bzero(carpr, sizeof(struct carpreq) * CARP_MAXVHID);
+ carpr[0].carpr_count = CARP_MAXVHID;
ifr.ifr_data = (caddr_t)&carpr;
if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
return;
- if (carpr.carpr_vhid > 0) {
- if (carpr.carpr_state > CARP_MAXSTATE)
- state = "<UNKNOWN>";
+ for (i = 0; i < carpr[0].carpr_count; i++) {
+ printf("\tcarp: %s vhid %d advbase %d advskew %d",
+ carp_states[carpr[i].carpr_state], carpr[i].carpr_vhid,
+ carpr[i].carpr_advbase, carpr[i].carpr_advskew);
+ if (printkeys && carpr[i].carpr_key[0] != '\0')
+ printf(" key \"%s\"\n", carpr[i].carpr_key);
else
- state = carp_states[carpr.carpr_state];
-
- printf("\tcarp: %s vhid %d advbase %d advskew %d\n",
- state, carpr.carpr_vhid, carpr.carpr_advbase,
- carpr.carpr_advskew);
+ printf("\n");
}
-
- return;
-
}
-void
-setcarp_passwd(const char *val, int d, int s, const struct afswtch *afp)
+static void
+setcarp_vhid(const char *val, int d, int s, const struct afswtch *afp)
{
- struct carpreq carpr;
-
- memset((char *)&carpr, 0, sizeof(struct carpreq));
- ifr.ifr_data = (caddr_t)&carpr;
- if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
- err(1, "SIOCGVH");
-
- memset(carpr.carpr_key, 0, sizeof(carpr.carpr_key));
- /* XXX Should hash the password into the key here, perhaps? */
- strlcpy(carpr.carpr_key, val, CARP_KEY_LEN);
-
- if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
- err(1, "SIOCSVH");
+ carpr_vhid = atoi(val);
+
+ if (carpr_vhid <= 0 || carpr_vhid > CARP_MAXVHID)
+ errx(1, "vhid must be greater than 0 and less than %u",
+ CARP_MAXVHID);
+
+ switch (afp->af_af) {
+#ifdef INET
+ case AF_INET:
+ {
+ struct in_aliasreq *ifra;
+
+ ifra = (struct in_aliasreq *)afp->af_addreq;
+ ifra->ifra_vhid = carpr_vhid;
+ break;
+ }
+#endif
+#ifdef INET6
+ case AF_INET6:
+ {
+ struct in6_aliasreq *ifra;
+
+ ifra = (struct in6_aliasreq *)afp->af_addreq;
+ ifra->ifra_vhid = carpr_vhid;
+ break;
+ }
+#endif
+ default:
+ errx(1, "%s doesn't support carp(4)", afp->af_name);
+ }
- return;
+ callback_register(setcarp_callback, NULL);
}
-void
-setcarp_vhid(const char *val, int d, int s, const struct afswtch *afp)
+static void
+setcarp_callback(int s, void *arg __unused)
{
- int vhid;
struct carpreq carpr;
- vhid = atoi(val);
-
- if (vhid <= 0)
- errx(1, "vhid must be greater than 0");
-
- memset((char *)&carpr, 0, sizeof(struct carpreq));
+ bzero(&carpr, sizeof(struct carpreq));
+ carpr.carpr_vhid = carpr_vhid;
+ carpr.carpr_count = 1;
ifr.ifr_data = (caddr_t)&carpr;
- if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
+ if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1 && errno != ENOENT)
err(1, "SIOCGVH");
- carpr.carpr_vhid = vhid;
+ if (carpr_key != NULL)
+ /* XXX Should hash the password into the key here? */
+ strlcpy(carpr.carpr_key, carpr_key, CARP_KEY_LEN);
+ if (carpr_advskew > -1)
+ carpr.carpr_advskew = carpr_advskew;
+ if (carpr_advbase > -1)
+ carpr.carpr_advbase = carpr_advbase;
+ if (carpr_state > -1)
+ carpr.carpr_state = carpr_state;
if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
err(1, "SIOCSVH");
-
- return;
}
-void
-setcarp_advskew(const char *val, int d, int s, const struct afswtch *afp)
+static void
+setcarp_passwd(const char *val, int d, int s, const struct afswtch *afp)
{
- int advskew;
- struct carpreq carpr;
-
- advskew = atoi(val);
- memset((char *)&carpr, 0, sizeof(struct carpreq));
- ifr.ifr_data = (caddr_t)&carpr;
+ if (carpr_vhid == -1)
+ errx(1, "passwd requires vhid");
- if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
- err(1, "SIOCGVH");
+ carpr_key = val;
+}
- carpr.carpr_advskew = advskew;
+static void
+setcarp_advskew(const char *val, int d, int s, const struct afswtch *afp)
+{
- if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
- err(1, "SIOCSVH");
+ if (carpr_vhid == -1)
+ errx(1, "advskew requires vhid");
- return;
+ carpr_advskew = atoi(val);
}
-void
+static void
setcarp_advbase(const char *val, int d, int s, const struct afswtch *afp)
{
- int advbase;
- struct carpreq carpr;
- advbase = atoi(val);
+ if (carpr_vhid == -1)
+ errx(1, "advbase requires vhid");
- memset((char *)&carpr, 0, sizeof(struct carpreq));
- ifr.ifr_data = (caddr_t)&carpr;
+ carpr_advbase = atoi(val);
+}
- if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
- err(1, "SIOCGVH");
+static void
+setcarp_state(const char *val, int d, int s, const struct afswtch *afp)
+{
+ int i;
- carpr.carpr_advbase = advbase;
+ if (carpr_vhid == -1)
+ errx(1, "state requires vhid");
- if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
- err(1, "SIOCSVH");
+ for (i = 0; i <= CARP_MAXSTATE; i++)
+ if (strcasecmp(carp_states[i], val) == 0) {
+ carpr_state = i;
+ return;
+ }
- return;
+ errx(1, "unknown state");
}
static struct cmd carp_cmds[] = {
@@ -180,6 +207,7 @@ static struct cmd carp_cmds[] = {
DEF_CMD_ARG("advskew", setcarp_advskew),
DEF_CMD_ARG("pass", setcarp_passwd),
DEF_CMD_ARG("vhid", setcarp_vhid),
+ DEF_CMD_ARG("state", setcarp_state),
};
static struct afswtch af_carp = {
.af_name = "af_carp",
diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8
index c6b8ea3..afee726 100644
--- a/sbin/ifconfig/ifconfig.8
+++ b/sbin/ifconfig/ifconfig.8
@@ -28,7 +28,7 @@
.\" From: @(#)ifconfig.8 8.3 (Berkeley) 1/5/94
.\" $FreeBSD$
.\"
-.Dd November 12, 2011
+.Dd December 16, 2011
.Dt IFCONFIG 8
.Os
.Sh NAME
@@ -2445,16 +2445,36 @@ The
argument is useless and hence deprecated.
.El
.Pp
-The following parameters are specific to
+The following parameters are used to configure
.Xr carp 4
-interfaces:
+protocol on an interface:
.Bl -tag -width indent
+.It Cm vhid Ar n
+Set the virtual host ID.
+This is a required setting to initiate
+.Xr carp 4 .
+If the virtual host ID doesn't exist yet, it is created and attached to the
+interface, otherwise configuration of an existing vhid is adjusted.
+If the
+.Cm vhid
+keyword is supplied along with an
+.Dq inet6
+or
+.Dq inet
+address, then this address is configured to be run under control of the
+specified vhid.
+Whenever a last address that refers to a particular vhid is removed from an
+interface, the vhid is automatically removed from interface and destroyed.
+Any other configuration parameters for the
+.Xr carp 4
+protocol should be supplied along with the
+.Cm vhid
+keyword.
+Acceptable values for vhid are 1 to 255.
.It Cm advbase Ar seconds
Specifies the base of the advertisement interval in seconds.
The acceptable values are 1 to 255.
The default value is 1.
-.\" The default value is
-.\" .Dv CARP_DFLTINTV .
.It Cm advskew Ar interval
Specifies the skew to add to the base advertisement interval to
make one host advertise slower than another host.
@@ -2464,10 +2484,8 @@ The default value is 0.
.It Cm pass Ar phrase
Set the authentication key to
.Ar phrase .
-.It Cm vhid Ar n
-Set the virtual host ID.
-This is a required setting.
-Acceptable values are 1 to 255.
+.It Cm state Ar MASTER|BACKUP
+Forcibly change state of a given vhid.
.El
.Pp
The
@@ -2530,8 +2548,9 @@ The
.Fl k
flag causes keying information for the interface, if available, to be
printed.
-For example, the values of 802.11 WEP keys will be printed, if accessible to
-the current user.
+For example, the values of 802.11 WEP keys and
+.Xr carp 4
+passphrases will be printed, if accessible to the current user.
This information is not printed by default, as it may be considered
sensitive.
.Pp
@@ -2593,6 +2612,11 @@ as a synonym for the canonical form of the option
.Fl alias :
.Dl # ifconfig em0 inet6 2001:db8:bdbd::123/48 delete
.Pp
+Configure a single CARP redundant address on igb0, and then switch it
+to be master:
+.Dl # ifconfig igb0 vhid 1 10.0.0.1/24 pass foobar
+.Dl # ifconfig igb0 vhid 1 state master
+.Pp
Configure the interface
.Li xl0 ,
to use 100baseTX, full duplex Ethernet media options:
diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c
index af280ce..0e3c3a3 100644
--- a/sbin/ifconfig/ifconfig.c
+++ b/sbin/ifconfig/ifconfig.c
@@ -1078,6 +1078,21 @@ printb(const char *s, unsigned v, const char *bits)
}
void
+print_vhid(const struct ifaddrs *ifa, const char *s)
+{
+ struct if_data *ifd;
+
+ if (ifa->ifa_data == NULL)
+ return;
+
+ ifd = ifa->ifa_data;
+ if (ifd->ifi_vhid == 0)
+ return;
+
+ printf("vhid %d ", ifd->ifi_vhid);
+}
+
+void
ifmaybeload(const char *name)
{
#define MOD_PREFIX_LEN 3 /* "if_" */
diff --git a/sbin/ifconfig/ifconfig.h b/sbin/ifconfig/ifconfig.h
index d6f5349..ea21db5 100644
--- a/sbin/ifconfig/ifconfig.h
+++ b/sbin/ifconfig/ifconfig.h
@@ -148,3 +148,6 @@ void clone_setdefcallback(const char *, clone_callback_func *);
* operations on ifmedia can avoid cmd line ordering confusion.
*/
struct ifmediareq *ifmedia_getstate(int s);
+
+void print_vhid(const struct ifaddrs *, const char *);
+
OpenPOWER on IntegriCloud