Discussion:
Why are you so mean dhclient ?
sven falempin
2016-02-05 20:40:21 UTC
Permalink
Dear Allmighty Tech Readers,

I recently found out that you cannot dhclient a carp iface.
People jumped over that saying , blahblah must have ip .
Lies ! CARP require the two interface to have the same ip,
the mac will be the same so using dhcp to configure them is
working by design.

I have now a working solution , it s ugly, please consider
helping cleaning
this for future openbsd, it s really an improvement.

I will follow demands to clean it.

Problems :
1/ an invalid carp iface that is up, is considered down (not fixed),
also send_msg is not possible on up carp without ip. Tested with ugly
second chunk of dhclient.c patch
2/ dhclient is only accepting 'hardware' mac address
3/ when configuring interface , routehandler is having a similar problem
than 1. First chunk in the diff

CARP is obvisouly smart to cut communication of a backup interface, but i
think
invalid state is not backup state. So to fix 1 i would somehow consider
active an invalid and up carp interface: make sense to me. This would fix
1.
For now i just put a stupid ip with /32 subnet....

2/ Is solved with the part of diff i think should be already integrated,
see dispatch.c
I am not sure if getifaddrs is badly coded though, and the sdl_type is
somehow not set.
carp GOT a mac address .

3/ Well i just cheated for this one , i am not good enough to play fair.


Index: dhclient.c
===================================================================
RCS file: /cvs/src/sbin/dhclient/dhclient.c,v
retrieving revision 1.361
diff -u -p -r1.361 dhclient.c
--- dhclient.c 18 May 2015 14:59:42 -0000 1.361
+++ dhclient.c 5 Feb 2016 20:22:16 -0000
@@ -323,6 +323,10 @@ routehandler(void)
ifm = (struct if_msghdr *)rtm;
if (ifm->ifm_index != ifi->index)
break;
+ if (0 == strncmp("carp", ifi->name, 4)) {
+ note("rtm->rtm_flags(%08X) :%08X", rtm->rtm_flags,
RTF_UP);
+ rtm->rtm_flags = rtm->rtm_flags | RTF_UP; // Can i
be more ugly ? i wonder
+ }
if ((rtm->rtm_flags & RTF_UP) == 0) {
rslt = asprintf(&errmsg, "%s down", ifi->name);
goto die;
@@ -634,6 +638,11 @@ state_preboot(void)

ifi->linkstat = interface_status(ifi->name);

+ if (0 == strncmp("carp", ifi->name, 4)) {
+ note("carp is not down it is invalid :s");
+ ifi->linkstat = 1;
+ }
+
if (log_perror && interval > 3) {
if (!preamble && !ifi->linkstat) {
fprintf(stderr, "%s: no link ....", ifi->name);
@@ -858,6 +867,8 @@ dhcpack(struct in_addr client_addr, stru

/* Stop resending DHCPREQUEST. */
cancel_timeout();
+
+ note("Hello , we just get the data right");

bind_lease();
}
Index: dispatch.c
===================================================================
RCS file: /cvs/src/sbin/dhclient/dispatch.c,v
retrieving revision 1.102
diff -u -p -r1.102 dispatch.c
--- dispatch.c 18 May 2015 14:59:42 -0000 1.102
+++ dispatch.c 5 Feb 2016 20:22:16 -0000
@@ -78,7 +78,7 @@ get_hw_address(void)
continue;

sdl = (struct sockaddr_dl *)ifa->ifa_addr;
- if (sdl->sdl_type != IFT_ETHER ||
+ if ( !( sdl->sdl_type == IFT_ETHER || sdl->sdl_type ==
IFT_CARP ) ||
sdl->sdl_alen != ETHER_ADDR_LEN)
continue;


Test:

# ifconfig em5 down; ifconfig em5 down #was having a address here to cvs
# ifconfig carp1 vhid 55 carpdev em5 169.0.0.1 netmask 32
# CFLAGS=-g make && ./dhclient -d carp1
cc -g -Wall -Werror-implicit-function-declaration -c dhclient.c
cc -static -pie -o dhclient dhclient.o clparse.o dispatch.o bpf.o
options.o conflex.o errwarn.o packet.o tables.o parse.o privsep.o kroute.
o -lutil
DHCPDISCOVER on carp1 - interval 3
DHCPOFFER from 192.168.10.1 (fe:e1:ba:d0:1e:0d)
DHCPREQUEST on carp1 to 255.255.255.255
DHCPACK from 192.168.10.1 (fe:e1:ba:d0:1e:0d)
Hello , we just get the data right
rtm->rtm_flags(FFFF8802) :00000001
bound to 192.168.10.151 -- renewal in 60 seconds.
# # can now cvs diff like normal

Redundancy must be easy.
sven falempin
2016-02-05 20:44:06 UTC
Permalink
Post by sven falempin
Dear Allmighty Tech Readers,
I recently found out that you cannot dhclient a carp iface.
People jumped over that saying , blahblah must have ip .
Lies ! CARP require the two interface to have the same ip,
the mac will be the same so using dhcp to configure them is
working by design.
I have now a working solution , it s ugly, please consider
helping cleaning
this for future openbsd, it s really an improvement.
I will follow demands to clean it.
1/ an invalid carp iface that is up, is considered down (not fixed),
also send_msg is not possible on up carp without ip. Tested with ugly
second chunk of dhclient.c patch
2/ dhclient is only accepting 'hardware' mac address
3/ when configuring interface , routehandler is having a similar problem
than 1. First chunk in the diff
CARP is obvisouly smart to cut communication of a backup interface, but i
think
invalid state is not backup state. So to fix 1 i would somehow consider
active an invalid and up carp interface: make sense to me. This would fix
1.
For now i just put a stupid ip with /32 subnet....
2/ Is solved with the part of diff i think should be already integrated,
see dispatch.c
I am not sure if getifaddrs is badly coded though, and the sdl_type is
somehow not set.
carp GOT a mac address .
3/ Well i just cheated for this one , i am not good enough to play fair.
Index: dhclient.c
===================================================================
RCS file: /cvs/src/sbin/dhclient/dhclient.c,v
retrieving revision 1.361
diff -u -p -r1.361 dhclient.c
--- dhclient.c 18 May 2015 14:59:42 -0000 1.361
+++ dhclient.c 5 Feb 2016 20:22:16 -0000
@@ -323,6 +323,10 @@ routehandler(void)
ifm = (struct if_msghdr *)rtm;
if (ifm->ifm_index != ifi->index)
break;
+ if (0 == strncmp("carp", ifi->name, 4)) {
+ note("rtm->rtm_flags(%08X) :%08X", rtm->rtm_flags,
RTF_UP);
+ rtm->rtm_flags = rtm->rtm_flags | RTF_UP; // Can
i be more ugly ? i wonder
+ }
if ((rtm->rtm_flags & RTF_UP) == 0) {
rslt = asprintf(&errmsg, "%s down", ifi->name);
goto die;
@@ -634,6 +638,11 @@ state_preboot(void)
ifi->linkstat = interface_status(ifi->name);
+ if (0 == strncmp("carp", ifi->name, 4)) {
+ note("carp is not down it is invalid :s");
+ ifi->linkstat = 1;
+ }
+
if (log_perror && interval > 3) {
if (!preamble && !ifi->linkstat) {
fprintf(stderr, "%s: no link ....", ifi->name);
@@ -858,6 +867,8 @@ dhcpack(struct in_addr client_addr, stru
/* Stop resending DHCPREQUEST. */
cancel_timeout();
+
+ note("Hello , we just get the data right");
bind_lease();
}
Index: dispatch.c
===================================================================
RCS file: /cvs/src/sbin/dhclient/dispatch.c,v
retrieving revision 1.102
diff -u -p -r1.102 dispatch.c
--- dispatch.c 18 May 2015 14:59:42 -0000 1.102
+++ dispatch.c 5 Feb 2016 20:22:16 -0000
@@ -78,7 +78,7 @@ get_hw_address(void)
continue;
sdl = (struct sockaddr_dl *)ifa->ifa_addr;
- if (sdl->sdl_type != IFT_ETHER ||
+ if ( !( sdl->sdl_type == IFT_ETHER || sdl->sdl_type ==
IFT_CARP ) ||
sdl->sdl_alen != ETHER_ADDR_LEN)
continue;
# ifconfig em5 down; ifconfig em5 down #was having a address here to cvs
# ifconfig carp1 vhid 55 carpdev em5 169.0.0.1 netmask 32
# CFLAGS=-g make && ./dhclient -d carp1
cc -g -Wall -Werror-implicit-function-declaration -c dhclient.c
cc -static -pie -o dhclient dhclient.o clparse.o dispatch.o bpf.o
options.o conflex.o errwarn.o packet.o tables.o parse.o privsep.o kroute.
o -lutil
DHCPDISCOVER on carp1 - interval 3
DHCPOFFER from 192.168.10.1 (fe:e1:ba:d0:1e:0d)
DHCPREQUEST on carp1 to 255.255.255.255
DHCPACK from 192.168.10.1 (fe:e1:ba:d0:1e:0d)
Hello , we just get the data right
rtm->rtm_flags(FFFF8802) :00000001
bound to 192.168.10.151 -- renewal in 60 seconds.
# # can now cvs diff like normal
PS: after first lease, the rtm flasg is up of course
bound to 192.168.10.151 -- renewal in 60 seconds.
rtm->rtm_flags(FFFF8843) :00000001
rtm->rtm_flags(FFFF8843) :00000001
DHCPREQUEST on carp1 to 192.168.10.1
--
---------------------------------------------------------------------------------------------------------------------
() ascii ribbon campaign - against html e-mail
/\
sven falempin
2016-02-05 22:11:02 UTC
Permalink
Post by sven falempin
Post by sven falempin
Dear Allmighty Tech Readers,
I recently found out that you cannot dhclient a carp iface.
People jumped over that saying , blahblah must have ip .
Lies ! CARP require the two interface to have the same ip,
the mac will be the same so using dhcp to configure them is
working by design.
I have now a working solution , it s ugly, please consider
helping cleaning
this for future openbsd, it s really an improvement.
I will follow demands to clean it.
1/ an invalid carp iface that is up, is considered down (not fixed),
also send_msg is not possible on up carp without ip. Tested with ugly
second chunk of dhclient.c patch
2/ dhclient is only accepting 'hardware' mac address
3/ when configuring interface , routehandler is having a similar problem
than 1. First chunk in the diff
CARP is obvisouly smart to cut communication of a backup interface, but i
think
invalid state is not backup state. So to fix 1 i would somehow consider
active an invalid and up carp interface: make sense to me. This would fix
1.
For now i just put a stupid ip with /32 subnet....
2/ Is solved with the part of diff i think should be already integrated,
see dispatch.c
I am not sure if getifaddrs is badly coded though, and the sdl_type is
somehow not set.
carp GOT a mac address .
3/ Well i just cheated for this one , i am not good enough to play fair.
Index: dhclient.c
===================================================================
RCS file: /cvs/src/sbin/dhclient/dhclient.c,v
retrieving revision 1.361
diff -u -p -r1.361 dhclient.c
--- dhclient.c 18 May 2015 14:59:42 -0000 1.361
+++ dhclient.c 5 Feb 2016 20:22:16 -0000
@@ -323,6 +323,10 @@ routehandler(void)
ifm = (struct if_msghdr *)rtm;
if (ifm->ifm_index != ifi->index)
break;
+ if (0 == strncmp("carp", ifi->name, 4)) {
+ note("rtm->rtm_flags(%08X) :%08X",
rtm->rtm_flags, RTF_UP);
+ rtm->rtm_flags = rtm->rtm_flags | RTF_UP; // Can
i be more ugly ? i wonder
+ }
if ((rtm->rtm_flags & RTF_UP) == 0) {
rslt = asprintf(&errmsg, "%s down", ifi->name);
goto die;
@@ -634,6 +638,11 @@ state_preboot(void)
ifi->linkstat = interface_status(ifi->name);
+ if (0 == strncmp("carp", ifi->name, 4)) {
+ note("carp is not down it is invalid :s");
+ ifi->linkstat = 1;
+ }
+
if (log_perror && interval > 3) {
if (!preamble && !ifi->linkstat) {
fprintf(stderr, "%s: no link ....", ifi->name);
@@ -858,6 +867,8 @@ dhcpack(struct in_addr client_addr, stru
/* Stop resending DHCPREQUEST. */
cancel_timeout();
+
+ note("Hello , we just get the data right");
bind_lease();
}
Index: dispatch.c
===================================================================
RCS file: /cvs/src/sbin/dhclient/dispatch.c,v
retrieving revision 1.102
diff -u -p -r1.102 dispatch.c
--- dispatch.c 18 May 2015 14:59:42 -0000 1.102
+++ dispatch.c 5 Feb 2016 20:22:16 -0000
@@ -78,7 +78,7 @@ get_hw_address(void)
continue;
sdl = (struct sockaddr_dl *)ifa->ifa_addr;
- if (sdl->sdl_type != IFT_ETHER ||
+ if ( !( sdl->sdl_type == IFT_ETHER || sdl->sdl_type ==
IFT_CARP ) ||
sdl->sdl_alen != ETHER_ADDR_LEN)
continue;
# ifconfig em5 down; ifconfig em5 down #was having a address here to cvs
# ifconfig carp1 vhid 55 carpdev em5 169.0.0.1 netmask 32
# CFLAGS=-g make && ./dhclient -d carp1
cc -g -Wall -Werror-implicit-function-declaration -c dhclient.c
cc -static -pie -o dhclient dhclient.o clparse.o dispatch.o bpf.o
options.o conflex.o errwarn.o packet.o tables.o parse.o privsep.o kroute.
o -lutil
DHCPDISCOVER on carp1 - interval 3
DHCPOFFER from 192.168.10.1 (fe:e1:ba:d0:1e:0d)
DHCPREQUEST on carp1 to 255.255.255.255
DHCPACK from 192.168.10.1 (fe:e1:ba:d0:1e:0d)
Hello , we just get the data right
rtm->rtm_flags(FFFF8802) :00000001
bound to 192.168.10.151 -- renewal in 60 seconds.
# # can now cvs diff like normal
PS: after first lease, the rtm flasg is up of course
bound to 192.168.10.151 -- renewal in 60 seconds.
rtm->rtm_flags(FFFF8843) :00000001
rtm->rtm_flags(FFFF8843) :00000001
DHCPREQUEST on carp1 to 192.168.10.1
--
---------------------------------------------------------------------------------------------------------------------
() ascii ribbon campaign - against html e-mail
/\
tl;dr
Digging a bit,

carp is not handle like other interface there is no if_carp.c file or
carp_X function.
In if.c, the case is handle with if type = IFT_CARP statement.
carp_carpdev_state is where the up/inactive reported status may be change,
in ./sys/netinet/ip_carp.c

for the ethernet address, a similar hax is made in the ioctl so set/get it:
case IFT_ETHER:
case IFT_CARP:
case IFT_XETHER:
case IFT_ISO88025:

So dhclient should align to this somehow:
- if (sdl->sdl_type != IFT_ETHER ||
+ int is_ether = sdl->sdl_type == IFT_ETHER || sdl->sdl_type
== IFT_CARP || sdl->sdl_type == IFT_XETHER || sdl->sdl_type == IFT_ISO88025;
+ if ( !( is_ether ) ||

getifsaddr calls sysctl_iflist, data from interface are dumped for the
client, thus finding the IFT_CARP
line 1291 of sys/net/rtsock.c: ifm->ifm_data = ifp->if_data;
in the carp AF_LINK entry.
tl;dr
--
---------------------------------------------------------------------------------------------------------------------
() ascii ribbon campaign - against html e-mail
/\
sven falempin
2016-02-07 03:35:27 UTC
Permalink
Post by sven falempin
tl;dr
Digging a bit,
carp is not handle like other interface there is no if_carp.c file or
carp_X function.
In if.c, the case is handle with if type = IFT_CARP statement.
carp_carpdev_state is where the up/inactive reported status may be change,
in ./sys/netinet/ip_carp.c
- if (sdl->sdl_type != IFT_ETHER ||
+ int is_ether = sdl->sdl_type == IFT_ETHER || sdl->sdl_type
== IFT_CARP || sdl->sdl_type == IFT_XETHER || sdl->sdl_type ==
IFT_ISO88025;
+ if ( !( is_ether ) ||
getifsaddr calls sysctl_iflist, data from interface are dumped for the
client, thus finding the IFT_CARP
line 1291 of sys/net/rtsock.c: ifm->ifm_data = ifp->if_data;
in the carp AF_LINK entry.
tl;dr
To send/receive the DHCP protocol, carp must accept ethernet data in INIT
MODE,
The IFF_RUNNING flag can be avoided or not.
With this, and the IFT_CARP in dhclient , carp can be initialized by dhcp.

/!\ invalid diff wont apply, and just work in progress

Index: ip_carp.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_carp.c,v
retrieving revision 1.264
diff -u -p -r1.264 ip_carp.c
--- ip_carp.c 2 Jul 2015 09:40:03 -0000 1.264
+++ ip_carp.c 7 Feb 2016 03:26:14 -0000
@@ -1394,9 +1396,19 @@ carp_ourether(void *v, u_int8_t *ena)

TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
struct carp_vhost_entry *vhe;
+ LIST_FOREACH(vhe, &vh->carp_vhosts, vhost_entries) {
+ if ( vhe->vhid == 0 ) {
+ printf("squeeeze\n");
+ continue; //no ethernet if no vhid (no in
ipv6 mode maybe :p
+ }
+ if (vhe->state == INIT && !memcmp(ena,
vhe->vhe_enaddr,ETHER_ADDR_LEN)) { //IFF_UP|IFF_RUNNING must be checked too
+ return (&vh->sc_if);
+ }
+ }
if ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
- (IFF_UP|IFF_RUNNING))
+ (IFF_UP|IFF_RUNNING)) {
continue;
+ }
if (vh->sc_balancing == CARP_BAL_ARP) {
LIST_FOREACH(vhe, &vh->carp_vhosts, vhost_entries)
if (vhe->state == MASTER &&
@@ -1426,9 +1438,15 @@ carp_input(struct ifnet *ifp0, struct mb
eh = mtod(m, struct ether_header *);
cif = (struct carp_if *)ifp0->if_carp;
ifp = carp_ourether(cif, eh->ether_dhost);
- if (ifp == NULL && !ETHER_IS_MULTICAST(eh->ether_dhost))
+ if (ifp == NULL && !ETHER_IS_MULTICAST(eh->ether_dhost)) {
return (0);
+ }

if (ifp == NULL) {
struct carp_softc *vh;
@@ -1567,15 +1586,22 @@ carp_setrun(struct carp_vhost_entry *vhe
sc->sc_realmac = 0;

if (sc->sc_if.if_flags & IFF_UP && vhe->vhid > 0 &&
- (sc->sc_naddrs || sc->sc_naddrs6) && !sc->sc_suppress) {
+ /*(sc->sc_naddrs || sc->sc_naddrs6) &&*/ !sc->sc_suppress) {
+ printf( "%s: SET IFF_RUNNING 2\n", sc->sc_if.if_xname);
sc->sc_if.if_flags |= IFF_RUNNING;
} else {
sc->sc_if.if_flags &= ~IFF_RUNNING;
return;
}
+ if ( !sc->sc_naddrs && !sc->sc_naddrs6 ) {
+ return;
+ }

switch (vhe->state) {
case INIT:
carp_set_state(vhe, BACKUP);
carp_setrun(vhe, 0);
break;
@@ -2314,6 +2341,14 @@ carp_output(struct ifnet *ifp, struct mb

vhe = sc->cur_vhe ? sc->cur_vhe : LIST_FIRST(&sc->carp_vhosts);

+
+ if ((vhe->state == INIT)
+ && !sc->sc_naddrs && !sc->sc_naddrs6 //just PARANOIA
+ && vhe->vhid > 0 && sc->sc_carpdev) { //actually an INVALID
STATE would be nice { INVALID =-1, INIT, BACKUP, MASTER}
+ return (ether_output(ifp, m, sa, rt));
+ }
+
if ((sc->sc_carpdev == NULL) ||
(!sc->sc_balancing && vhe->state != MASTER)) {
m_freem(m);
@@ -2329,6 +2364,12 @@ carp_set_state_all(struct carp_softc *sc
struct carp_vhost_entry *vhe;

LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries) {
+ if (vhe->state == INIT && vhe->vhid > 0) {
+ if (!sc->sc_naddrs && !sc->sc_naddrs6)
+ sc->sc_if.if_link_state = LINK_STATE_UP;
//we have mac, IP is down, but iface is ethernet valid
+ }
if (vhe->state == state)
continue;

@@ -2373,6 +2414,12 @@ carp_set_state(struct carp_vhost_entry *
case MASTER:
sc->sc_if.if_link_state = LINK_STATE_UP;
break;
+ case INIT:
+ if (sc->sc_naddrs || sc->sc_naddrs6) //MUST HAVE vhid too
+ sc->sc_if.if_link_state = LINK_STATE_DOWN;
+ else
+ sc->sc_if.if_link_state = LINK_STATE_UP;
+ break;
default:
sc->sc_if.if_link_state = LINK_STATE_INVALID;
break;
--
---------------------------------------------------------------------------------------------------------------------
() ascii ribbon campaign - against html e-mail
/\
Loading...