rad(8) and carp interfaces

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

rad(8) and carp interfaces

Matthieu Herrb-3
Hi,

I've a pair of redundant routers, which need to run rad(8) on the
internal interfaces.

But using carp, on the inactive router, rad complains every
time it tries to send a RA:

 rad[65590]: sendmsg on carp2: Can't assign requested address

Which I can understand since it currently doesnt "own" the shared IPv6
address of the carp interface.

Is there a way to configure rad to avoid these errors?
How do other people handle the situation?

Thanks in advance,
--
Matthieu Herrb

Reply | Threaded
Open this post in threaded view
|

Re: rad(8) and carp interfaces

Sebastian Benoit-3
Matthieu Herrb([hidden email]) on 2019.09.04 18:07:35 +0200:

> Hi,
>
> I've a pair of redundant routers, which need to run rad(8) on the
> internal interfaces.
>
> But using carp, on the inactive router, rad complains every
> time it tries to send a RA:
>
>  rad[65590]: sendmsg on carp2: Can't assign requested address
>
> Which I can understand since it currently doesnt "own" the shared IPv6
> address of the carp interface.

correct. rad(8) needs to look at the interface state to not try sending on
a (carp) interface that is in backup state, or just not print this warning
at all. It is possible to monitor the link state since the frontend process
already has a route socket and could certainly track the link state, buts
its a little bit of work.
 
> Is there a way to configure rad to avoid these errors?

At the moment none other than patching out the log_warn().

> How do other people handle the situation?
>
> Thanks in advance,
> --
> Matthieu Herrb
>

Unrelated, but noticed by florian, this bit in the manpage is no longer
needed since he removed soii for link-local adresses in
sys/netinet6/in6_ifattach.c rev 1.114

ok?

diff b31eb29f59f3580445ea0341b271e321d53958a6 /opt/git/benoit/src
blob - d93e64d4648dfe25a5c76faac3994780d1ce02f8
file + usr.sbin/rad/rad.8
--- usr.sbin/rad/rad.8
+++ usr.sbin/rad/rad.8
@@ -146,15 +146,3 @@ The
 .Nm
 program was written by
 .An Florian Obser Aq Mt [hidden email] .
-.Sh CAVEATS
-When running
-.Nm
-on a
-.Xr carp 4
-interface, it is recommended to either disable SOIIs (persistent Semantically
-Opaque Interface Identifiers) on the interface with
-.Xr ifconfig 8 ,
-or ensure that all CARP peers have the same SOII key stored in
-.Pa /etc/soii.key .
-Otherwise the default IPv6 router's link-local address will change during CARP
-failover, which temporarily disrupts connectivity of IPv6 autoconf clients.

Reply | Threaded
Open this post in threaded view
|

Re: rad(8) and carp interfaces

Klemens Nanni-2
On Thu, Sep 05, 2019 at 10:32:25AM +0200, Sebastian Benoit wrote:
> Unrelated, but noticed by florian, this bit in the manpage is no longer
> needed since he removed soii for link-local adresses in
> sys/netinet6/in6_ifattach.c rev 1.114
Good catch, OK kn.

Reply | Threaded
Open this post in threaded view
|

Re: rad(8) and carp interfaces

Florian Obser-2
In reply to this post by Matthieu Herrb-3
On Wed, Sep 04, 2019 at 06:07:35PM +0200, Matthieu Herrb wrote:

> Hi,
>
> I've a pair of redundant routers, which need to run rad(8) on the
> internal interfaces.
>
> But using carp, on the inactive router, rad complains every
> time it tries to send a RA:
>
>  rad[65590]: sendmsg on carp2: Can't assign requested address
>
> Which I can understand since it currently doesnt "own" the shared IPv6
> address of the carp interface.
>
> Is there a way to configure rad to avoid these errors?
> How do other people handle the situation?
>
> Thanks in advance,
> --
> Matthieu Herrb
>

This should keep the noise down.

OK?

diff --git frontend.c frontend.c
index 8178b058629..920e9b7077c 100644
--- frontend.c
+++ frontend.c
@@ -104,6 +104,7 @@ struct ra_iface {
  char conf_name[IF_NAMESIZE];
  uint32_t if_index;
  int removed;
+ int link_state;
  int prefix_count;
  size_t datalen;
  uint8_t data[RA_MAX_SIZE];
@@ -117,6 +118,7 @@ void frontend_startup(void);
 void icmp6_receive(int, short, void *);
 void join_all_routers_mcast_group(struct ra_iface *);
 void leave_all_routers_mcast_group(struct ra_iface *);
+int get_link_state(char *);
 void merge_ra_interface(char *, char *);
 void merge_ra_interfaces(void);
 struct ra_iface *find_ra_iface_by_id(uint32_t);
@@ -720,21 +722,59 @@ find_ra_iface_conf(struct ra_iface_conf_head *head, char *if_name)
  return (NULL);
 }
 
+int
+get_link_state(char *if_name)
+{
+ struct ifaddrs *ifap, *ifa;
+ int ls = LINK_STATE_UNKNOWN;
+
+ if (getifaddrs(&ifap) != 0) {
+ log_warn("getifaddrs");
+ return LINK_STATE_UNKNOWN;
+ }
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family != AF_LINK)
+ continue;
+ if (strcmp(if_name, ifa->ifa_name) != 0)
+ continue;
+
+ ls = ((struct if_data*)ifa->ifa_data)->ifi_link_state;
+ break;
+ }
+ freeifaddrs(ifap);
+ return ls;
+}
+
 void
 merge_ra_interface(char *name, char *conf_name)
 {
  struct ra_iface *ra_iface;
  uint32_t if_index;
+ int link_state;
+
+ link_state = get_link_state(name);
 
  if ((ra_iface = find_ra_iface_by_name(name)) != NULL) {
- log_debug("keeping interface %s", name);
- ra_iface->removed = 0;
+ ra_iface->link_state = link_state;
+ if (link_state == LINK_STATE_DOWN) {
+ log_debug("%s down, ignoring", name);
+ ra_iface->removed = 1;
+ } else {
+ log_debug("keeping interface %s", name);
+ ra_iface->removed = 0;
+ }
+ return;
+ }
+
+ if (link_state == LINK_STATE_DOWN) {
+ log_debug("%s down, ignoring", name);
  return;
  }
 
  log_debug("new interface %s", name);
  if ((if_index = if_nametoindex(name)) == 0)
  return;
+
  log_debug("adding interface %s", name);
  if ((ra_iface = calloc(1, sizeof(*ra_iface))) == NULL)
  fatal("%s", __func__);
@@ -1135,6 +1175,9 @@ ra_output(struct ra_iface *ra_iface, struct sockaddr_in6 *to)
  ssize_t len;
  int hoplimit = 255;
 
+ if (ra_iface->link_state == LINK_STATE_DOWN)
+ return;
+
  sndmhdr.msg_name = to;
  sndmhdr.msg_iov[0].iov_base = ra_iface->data;
  sndmhdr.msg_iov[0].iov_len = ra_iface->datalen;


--
I'm not entirely sure you are real.

Reply | Threaded
Open this post in threaded view
|

Re: rad(8) and carp interfaces

Sebastian Benoit-3
Florian Obser([hidden email]) on 2019.09.06 16:51:35 +0200:

> On Wed, Sep 04, 2019 at 06:07:35PM +0200, Matthieu Herrb wrote:
> > Hi,
> >
> > I've a pair of redundant routers, which need to run rad(8) on the
> > internal interfaces.
> >
> > But using carp, on the inactive router, rad complains every
> > time it tries to send a RA:
> >
> >  rad[65590]: sendmsg on carp2: Can't assign requested address
> >
> > Which I can understand since it currently doesnt "own" the shared IPv6
> > address of the carp interface.
> >
> > Is there a way to configure rad to avoid these errors?
> > How do other people handle the situation?
> >
> > Thanks in advance,
> > --
> > Matthieu Herrb
> >
>
> This should keep the noise down.
>
> OK?

comment inline

>
> diff --git frontend.c frontend.c
> index 8178b058629..920e9b7077c 100644
> --- frontend.c
> +++ frontend.c
> @@ -104,6 +104,7 @@ struct ra_iface {
>   char conf_name[IF_NAMESIZE];
>   uint32_t if_index;
>   int removed;
> + int link_state;
>   int prefix_count;
>   size_t datalen;
>   uint8_t data[RA_MAX_SIZE];
> @@ -117,6 +118,7 @@ void frontend_startup(void);
>  void icmp6_receive(int, short, void *);
>  void join_all_routers_mcast_group(struct ra_iface *);
>  void leave_all_routers_mcast_group(struct ra_iface *);
> +int get_link_state(char *);
>  void merge_ra_interface(char *, char *);
>  void merge_ra_interfaces(void);
>  struct ra_iface *find_ra_iface_by_id(uint32_t);
> @@ -720,21 +722,59 @@ find_ra_iface_conf(struct ra_iface_conf_head *head, char *if_name)
>   return (NULL);
>  }
>  
> +int
> +get_link_state(char *if_name)
> +{
> + struct ifaddrs *ifap, *ifa;
> + int ls = LINK_STATE_UNKNOWN;
> +
> + if (getifaddrs(&ifap) != 0) {
> + log_warn("getifaddrs");
> + return LINK_STATE_UNKNOWN;
> + }
> + for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
> + if (ifa->ifa_addr->sa_family != AF_LINK)
> + continue;
> + if (strcmp(if_name, ifa->ifa_name) != 0)
> + continue;
> +
> + ls = ((struct if_data*)ifa->ifa_data)->ifi_link_state;
> + break;
> + }
> + freeifaddrs(ifap);
> + return ls;
> +}
> +
>  void
>  merge_ra_interface(char *name, char *conf_name)
>  {
>   struct ra_iface *ra_iface;
>   uint32_t if_index;
> + int link_state;
> +
> + link_state = get_link_state(name);
>  
>   if ((ra_iface = find_ra_iface_by_name(name)) != NULL) {
> - log_debug("keeping interface %s", name);
> - ra_iface->removed = 0;
> + ra_iface->link_state = link_state;
> + if (link_state == LINK_STATE_DOWN) {

note that there are some (physical) interfaces that do not report a link
state and thus are unknown even when they can send packets.
Use the LINK_STATE_IS_UP() macro here.

Do we need to consider the case of an interface being administratively down
here (!(ifap->flags & IFF_UP))?.


> + log_debug("%s down, ignoring", name);
> + ra_iface->removed = 1;
> + } else {
> + log_debug("keeping interface %s", name);
> + ra_iface->removed = 0;
> + }
> + return;
> + }
> +
> + if (link_state == LINK_STATE_DOWN) {
> + log_debug("%s down, ignoring", name);
>   return;
>   }
>  
>   log_debug("new interface %s", name);
>   if ((if_index = if_nametoindex(name)) == 0)
>   return;
> +
>   log_debug("adding interface %s", name);
>   if ((ra_iface = calloc(1, sizeof(*ra_iface))) == NULL)
>   fatal("%s", __func__);
> @@ -1135,6 +1175,9 @@ ra_output(struct ra_iface *ra_iface, struct sockaddr_in6 *to)
>   ssize_t len;
>   int hoplimit = 255;
>  
> + if (ra_iface->link_state == LINK_STATE_DOWN)
> + return;
> +
>   sndmhdr.msg_name = to;
>   sndmhdr.msg_iov[0].iov_base = ra_iface->data;
>   sndmhdr.msg_iov[0].iov_len = ra_iface->datalen;
>
>
> --
> I'm not entirely sure you are real.
>

Reply | Threaded
Open this post in threaded view
|

Re: rad(8) and carp interfaces

Florian Obser-2
On Fri, Sep 06, 2019 at 09:15:16PM +0200, Sebastian Benoit wrote:

> Florian Obser([hidden email]) on 2019.09.06 16:51:35 +0200:
> > On Wed, Sep 04, 2019 at 06:07:35PM +0200, Matthieu Herrb wrote:
> > > Hi,
> > >
> > > I've a pair of redundant routers, which need to run rad(8) on the
> > > internal interfaces.
> > >
> > > But using carp, on the inactive router, rad complains every
> > > time it tries to send a RA:
> > >
> > >  rad[65590]: sendmsg on carp2: Can't assign requested address
> > >
> > > Which I can understand since it currently doesnt "own" the shared IPv6
> > > address of the carp interface.
> > >
> > > Is there a way to configure rad to avoid these errors?
> > > How do other people handle the situation?
> > >
> > > Thanks in advance,
> > > --
> > > Matthieu Herrb
> > >
> >
> > This should keep the noise down.
> >
> > OK?
>
> comment inline
>
> >   if ((ra_iface = find_ra_iface_by_name(name)) != NULL) {
> > - log_debug("keeping interface %s", name);
> > - ra_iface->removed = 0;
> > + ra_iface->link_state = link_state;
> > + if (link_state == LINK_STATE_DOWN) {
>
> note that there are some (physical) interfaces that do not report a link
> state and thus are unknown even when they can send packets.

I know, observe how I don't care about UP but rather DOWN.

> Use the LINK_STATE_IS_UP() macro here.

Probably best to use !LINK_STATE_IS_UP() :P

>
> Do we need to consider the case of an interface being administratively down
> here (!(ifap->flags & IFF_UP))?.

I checked, no. sendmsg doesn't error out, the packet is just not going
out. I would leave it at that.

diff --git frontend.c frontend.c
index 8178b058629..3cf52fb4127 100644
--- frontend.c
+++ frontend.c
@@ -104,6 +104,7 @@ struct ra_iface {
  char conf_name[IF_NAMESIZE];
  uint32_t if_index;
  int removed;
+ int link_state;
  int prefix_count;
  size_t datalen;
  uint8_t data[RA_MAX_SIZE];
@@ -117,6 +118,7 @@ void frontend_startup(void);
 void icmp6_receive(int, short, void *);
 void join_all_routers_mcast_group(struct ra_iface *);
 void leave_all_routers_mcast_group(struct ra_iface *);
+int get_link_state(char *);
 void merge_ra_interface(char *, char *);
 void merge_ra_interfaces(void);
 struct ra_iface *find_ra_iface_by_id(uint32_t);
@@ -720,21 +722,59 @@ find_ra_iface_conf(struct ra_iface_conf_head *head, char *if_name)
  return (NULL);
 }
 
+int
+get_link_state(char *if_name)
+{
+ struct ifaddrs *ifap, *ifa;
+ int ls = LINK_STATE_UNKNOWN;
+
+ if (getifaddrs(&ifap) != 0) {
+ log_warn("getifaddrs");
+ return LINK_STATE_UNKNOWN;
+ }
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family != AF_LINK)
+ continue;
+ if (strcmp(if_name, ifa->ifa_name) != 0)
+ continue;
+
+ ls = ((struct if_data*)ifa->ifa_data)->ifi_link_state;
+ break;
+ }
+ freeifaddrs(ifap);
+ return ls;
+}
+
 void
 merge_ra_interface(char *name, char *conf_name)
 {
  struct ra_iface *ra_iface;
  uint32_t if_index;
+ int link_state;
+
+ link_state = get_link_state(name);
 
  if ((ra_iface = find_ra_iface_by_name(name)) != NULL) {
- log_debug("keeping interface %s", name);
- ra_iface->removed = 0;
+ ra_iface->link_state = link_state;
+ if (!LINK_STATE_IS_UP(link_state)) {
+ log_debug("%s down, ignoring", name);
+ ra_iface->removed = 1;
+ } else {
+ log_debug("keeping interface %s", name);
+ ra_iface->removed = 0;
+ }
+ return;
+ }
+
+ if (!LINK_STATE_IS_UP(link_state)) {
+ log_debug("%s down, ignoring", name);
  return;
  }
 
  log_debug("new interface %s", name);
  if ((if_index = if_nametoindex(name)) == 0)
  return;
+
  log_debug("adding interface %s", name);
  if ((ra_iface = calloc(1, sizeof(*ra_iface))) == NULL)
  fatal("%s", __func__);
@@ -1135,6 +1175,9 @@ ra_output(struct ra_iface *ra_iface, struct sockaddr_in6 *to)
  ssize_t len;
  int hoplimit = 255;
 
+ if (!LINK_STATE_IS_UP(ra_iface->link_state))
+ return;
+
  sndmhdr.msg_name = to;
  sndmhdr.msg_iov[0].iov_base = ra_iface->data;
  sndmhdr.msg_iov[0].iov_len = ra_iface->datalen;


--
I'm not entirely sure you are real.

Reply | Threaded
Open this post in threaded view
|

Re: rad(8) and carp interfaces

Sebastian Benoit-3
ok

Florian Obser([hidden email]) on 2019.09.07 09:11:36 +0200:

> On Fri, Sep 06, 2019 at 09:15:16PM +0200, Sebastian Benoit wrote:
> > Florian Obser([hidden email]) on 2019.09.06 16:51:35 +0200:
> > > On Wed, Sep 04, 2019 at 06:07:35PM +0200, Matthieu Herrb wrote:
> > > > Hi,
> > > >
> > > > I've a pair of redundant routers, which need to run rad(8) on the
> > > > internal interfaces.
> > > >
> > > > But using carp, on the inactive router, rad complains every
> > > > time it tries to send a RA:
> > > >
> > > >  rad[65590]: sendmsg on carp2: Can't assign requested address
> > > >
> > > > Which I can understand since it currently doesnt "own" the shared IPv6
> > > > address of the carp interface.
> > > >
> > > > Is there a way to configure rad to avoid these errors?
> > > > How do other people handle the situation?
> > > >
> > > > Thanks in advance,
> > > > --
> > > > Matthieu Herrb
> > > >
> > >
> > > This should keep the noise down.
> > >
> > > OK?
> >
> > comment inline
> >
> > >   if ((ra_iface = find_ra_iface_by_name(name)) != NULL) {
> > > - log_debug("keeping interface %s", name);
> > > - ra_iface->removed = 0;
> > > + ra_iface->link_state = link_state;
> > > + if (link_state == LINK_STATE_DOWN) {
> >
> > note that there are some (physical) interfaces that do not report a link
> > state and thus are unknown even when they can send packets.
>
> I know, observe how I don't care about UP but rather DOWN.
>
> > Use the LINK_STATE_IS_UP() macro here.
>
> Probably best to use !LINK_STATE_IS_UP() :P
>
> >
> > Do we need to consider the case of an interface being administratively down
> > here (!(ifap->flags & IFF_UP))?.
>
> I checked, no. sendmsg doesn't error out, the packet is just not going
> out. I would leave it at that.
>
> diff --git frontend.c frontend.c
> index 8178b058629..3cf52fb4127 100644
> --- frontend.c
> +++ frontend.c
> @@ -104,6 +104,7 @@ struct ra_iface {
>   char conf_name[IF_NAMESIZE];
>   uint32_t if_index;
>   int removed;
> + int link_state;
>   int prefix_count;
>   size_t datalen;
>   uint8_t data[RA_MAX_SIZE];
> @@ -117,6 +118,7 @@ void frontend_startup(void);
>  void icmp6_receive(int, short, void *);
>  void join_all_routers_mcast_group(struct ra_iface *);
>  void leave_all_routers_mcast_group(struct ra_iface *);
> +int get_link_state(char *);
>  void merge_ra_interface(char *, char *);
>  void merge_ra_interfaces(void);
>  struct ra_iface *find_ra_iface_by_id(uint32_t);
> @@ -720,21 +722,59 @@ find_ra_iface_conf(struct ra_iface_conf_head *head, char *if_name)
>   return (NULL);
>  }
>  
> +int
> +get_link_state(char *if_name)
> +{
> + struct ifaddrs *ifap, *ifa;
> + int ls = LINK_STATE_UNKNOWN;
> +
> + if (getifaddrs(&ifap) != 0) {
> + log_warn("getifaddrs");
> + return LINK_STATE_UNKNOWN;
> + }
> + for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
> + if (ifa->ifa_addr->sa_family != AF_LINK)
> + continue;
> + if (strcmp(if_name, ifa->ifa_name) != 0)
> + continue;
> +
> + ls = ((struct if_data*)ifa->ifa_data)->ifi_link_state;
> + break;
> + }
> + freeifaddrs(ifap);
> + return ls;
> +}
> +
>  void
>  merge_ra_interface(char *name, char *conf_name)
>  {
>   struct ra_iface *ra_iface;
>   uint32_t if_index;
> + int link_state;
> +
> + link_state = get_link_state(name);
>  
>   if ((ra_iface = find_ra_iface_by_name(name)) != NULL) {
> - log_debug("keeping interface %s", name);
> - ra_iface->removed = 0;
> + ra_iface->link_state = link_state;
> + if (!LINK_STATE_IS_UP(link_state)) {
> + log_debug("%s down, ignoring", name);
> + ra_iface->removed = 1;
> + } else {
> + log_debug("keeping interface %s", name);
> + ra_iface->removed = 0;
> + }
> + return;
> + }
> +
> + if (!LINK_STATE_IS_UP(link_state)) {
> + log_debug("%s down, ignoring", name);
>   return;
>   }
>  
>   log_debug("new interface %s", name);
>   if ((if_index = if_nametoindex(name)) == 0)
>   return;
> +
>   log_debug("adding interface %s", name);
>   if ((ra_iface = calloc(1, sizeof(*ra_iface))) == NULL)
>   fatal("%s", __func__);
> @@ -1135,6 +1175,9 @@ ra_output(struct ra_iface *ra_iface, struct sockaddr_in6 *to)
>   ssize_t len;
>   int hoplimit = 255;
>  
> + if (!LINK_STATE_IS_UP(ra_iface->link_state))
> + return;
> +
>   sndmhdr.msg_name = to;
>   sndmhdr.msg_iov[0].iov_base = ra_iface->data;
>   sndmhdr.msg_iov[0].iov_len = ra_iface->datalen;
>
>
> --
> I'm not entirely sure you are real.
>