[v2] uapi glibc compat: fix compile errors when glibc net/if.h included before linux/if.h

Message ID 1461512707-23058-1-git-send-email-mikko.rapeli@iki.fi
State New, archived
Headers

Commit Message

Mikko Rapeli April 24, 2016, 3:45 p.m. UTC
  glibc's net/if.h contains copies of definitions from linux/if.h and these
conflict and cause build failures if both files are included by application
source code. Changes in uapi headers, which fixed header file dependencies to
include linux/if.h when it was needed, e.g. commit 1ffad83d, made the
net/if.h and linux/if.h incompatibilities visible as build failures for
userspace applications like iproute2 and xtables-addons.

This patch fixes compile errors when glibc net/if.h is included before
linux/if.h:

./linux/if.h:99:21: error: redeclaration of enumerator ‘IFF_NOARP’
./linux/if.h:98:23: error: redeclaration of enumerator ‘IFF_RUNNING’
./linux/if.h:97:26: error: redeclaration of enumerator ‘IFF_NOTRAILERS’
./linux/if.h:96:27: error: redeclaration of enumerator ‘IFF_POINTOPOINT’
./linux/if.h:95:24: error: redeclaration of enumerator ‘IFF_LOOPBACK’
./linux/if.h:94:21: error: redeclaration of enumerator ‘IFF_DEBUG’
./linux/if.h:93:25: error: redeclaration of enumerator ‘IFF_BROADCAST’
./linux/if.h:92:19: error: redeclaration of enumerator ‘IFF_UP’
./linux/if.h:252:8: error: redefinition of ‘struct ifconf’
./linux/if.h:203:8: error: redefinition of ‘struct ifreq’
./linux/if.h:169:8: error: redefinition of ‘struct ifmap’
./linux/if.h:107:23: error: redeclaration of enumerator ‘IFF_DYNAMIC’
./linux/if.h:106:25: error: redeclaration of enumerator ‘IFF_AUTOMEDIA’
./linux/if.h:105:23: error: redeclaration of enumerator ‘IFF_PORTSEL’
./linux/if.h:104:25: error: redeclaration of enumerator ‘IFF_MULTICAST’
./linux/if.h:103:21: error: redeclaration of enumerator ‘IFF_SLAVE’
./linux/if.h:102:22: error: redeclaration of enumerator ‘IFF_MASTER’
./linux/if.h:101:24: error: redeclaration of enumerator ‘IFF_ALLMULTI’
./linux/if.h:100:23: error: redeclaration of enumerator ‘IFF_PROMISC’

The cases where linux/if.h is included before net/if.h need a similar fix in
the glibc side, or the order of include files can be changed userspace
code as a workaround.

This change was tested in x86 userspace on Debian unstable with
scripts/headers_compile_test.sh:

$ make headers_install && \
  cd usr/include && ../../scripts/headers_compile_test.sh -l -k
...
cc -Wall -c -nostdinc -I /usr/lib/gcc/i586-linux-gnu/5/include -I /usr/lib/gcc/i586-linux-gnu/5/include-fixed -I . -I /home/mcfrisk/src/linux-2.6/usr/headers_compile_test_include.2uX2zH -I /home/mcfrisk/src/linux-2.6/usr/headers_compile_test_include.2uX2zH/i586-linux-gnu -o /dev/null ./linux/if.h_libc_before_kernel.h
PASSED libc before kernel test: ./linux/if.h

Reported-by: Jan Engelhardt <jengelh@inai.de>
Reported-by: Josh Boyer <jwboyer@fedoraproject.org>
Reported-by: Stephen Hemminger <shemming@brocade.com>
Reported-by: Waldemar Brodkorb <mail@waldemar-brodkorb.de>
Cc: Gabriel Laskar <gabriel@lse.epita.fr>
Signed-off-by: Mikko Rapeli <mikko.rapeli@iki.fi>
---
 include/uapi/linux/if.h          | 28 +++++++++++++++++++++++++
 include/uapi/linux/libc-compat.h | 44 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 72 insertions(+)

v1:
http://marc.info/?l=linux-kernel&m=145485386721798&w=2

v2:
Added handling for net_device_flags IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO
which are unknown to glibc as suggested by David Miller in
http://marc.info/?l=linux-kernel&m=145650410726228&w=2
  

Comments

Szabolcs Nagy April 25, 2016, 11:26 a.m. UTC | #1
On 24/04/16 16:45, Mikko Rapeli wrote:
> glibc's net/if.h contains copies of definitions from linux/if.h and these
> conflict and cause build failures if both files are included by application
> source code. Changes in uapi headers, which fixed header file dependencies to
> include linux/if.h when it was needed, e.g. commit 1ffad83d, made the
> net/if.h and linux/if.h incompatibilities visible as build failures for
> userspace applications like iproute2 and xtables-addons.
> 
> This patch fixes compile errors when glibc net/if.h is included before
> linux/if.h:
> 

there should be a way to turn the conflicting definitions
off if a libc header is included first. (the other direction
won't work in general because linux definitions can be wrong
for user space.)

currently the only way to avoid the conflict is to define
__GLIBC__ and a handful of glibc include guard macros that
are not part of any public api, so a libc implementation
might not want to do this.

e.g. the kernel could turn off the potentially conflicting
definitions if the libc defines __LIBC_WANTS_NO_UAPI_DEFS
(it can use finer grain control, but there should be a
non-glibc specific way to do this).
  
Mikko Rapeli April 25, 2016, 12:13 p.m. UTC | #2
On Mon, Apr 25, 2016 at 12:26:09PM +0100, Szabolcs Nagy wrote:
> On 24/04/16 16:45, Mikko Rapeli wrote:
> > glibc's net/if.h contains copies of definitions from linux/if.h and these
> > conflict and cause build failures if both files are included by application
> > source code. Changes in uapi headers, which fixed header file dependencies to
> > include linux/if.h when it was needed, e.g. commit 1ffad83d, made the
> > net/if.h and linux/if.h incompatibilities visible as build failures for
> > userspace applications like iproute2 and xtables-addons.
> > 
> > This patch fixes compile errors when glibc net/if.h is included before
> > linux/if.h:
> > 
> 
> there should be a way to turn the conflicting definitions
> off if a libc header is included first. (the other direction
> won't work in general because linux definitions can be wrong
> for user space.)
>
> currently the only way to avoid the conflict is to define
> __GLIBC__ and a handful of glibc include guard macros that
> are not part of any public api, so a libc implementation
> might not want to do this.
> 
> e.g. the kernel could turn off the potentially conflicting
> definitions if the libc defines __LIBC_WANTS_NO_UAPI_DEFS
> (it can use finer grain control, but there should be a
> non-glibc specific way to do this).

True. Maybe Linux kernel could allow non-glibc userspace headers to define
__UAPI_DEF's as they wish but fall back to a default 1 as in lines after:

https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/libc-compat.h#n118

But sometimes users run old libc's and want to use shiny features from newer
kernel and thus use kernel headers for some extra definitions to existing
libc headers and use them in system calls.

Driver specific ioctl's are a good example.

-Mikko
  
Josh Boyer May 9, 2016, 1:59 p.m. UTC | #3
On Sun, Apr 24, 2016 at 11:45 AM, Mikko Rapeli <mikko.rapeli@iki.fi> wrote:
> glibc's net/if.h contains copies of definitions from linux/if.h and these
> conflict and cause build failures if both files are included by application
> source code. Changes in uapi headers, which fixed header file dependencies to
> include linux/if.h when it was needed, e.g. commit 1ffad83d, made the
> net/if.h and linux/if.h incompatibilities visible as build failures for
> userspace applications like iproute2 and xtables-addons.
>
> This patch fixes compile errors when glibc net/if.h is included before
> linux/if.h:
>
> ./linux/if.h:99:21: error: redeclaration of enumerator ‘IFF_NOARP’
> ./linux/if.h:98:23: error: redeclaration of enumerator ‘IFF_RUNNING’
> ./linux/if.h:97:26: error: redeclaration of enumerator ‘IFF_NOTRAILERS’
> ./linux/if.h:96:27: error: redeclaration of enumerator ‘IFF_POINTOPOINT’
> ./linux/if.h:95:24: error: redeclaration of enumerator ‘IFF_LOOPBACK’
> ./linux/if.h:94:21: error: redeclaration of enumerator ‘IFF_DEBUG’
> ./linux/if.h:93:25: error: redeclaration of enumerator ‘IFF_BROADCAST’
> ./linux/if.h:92:19: error: redeclaration of enumerator ‘IFF_UP’
> ./linux/if.h:252:8: error: redefinition of ‘struct ifconf’
> ./linux/if.h:203:8: error: redefinition of ‘struct ifreq’
> ./linux/if.h:169:8: error: redefinition of ‘struct ifmap’
> ./linux/if.h:107:23: error: redeclaration of enumerator ‘IFF_DYNAMIC’
> ./linux/if.h:106:25: error: redeclaration of enumerator ‘IFF_AUTOMEDIA’
> ./linux/if.h:105:23: error: redeclaration of enumerator ‘IFF_PORTSEL’
> ./linux/if.h:104:25: error: redeclaration of enumerator ‘IFF_MULTICAST’
> ./linux/if.h:103:21: error: redeclaration of enumerator ‘IFF_SLAVE’
> ./linux/if.h:102:22: error: redeclaration of enumerator ‘IFF_MASTER’
> ./linux/if.h:101:24: error: redeclaration of enumerator ‘IFF_ALLMULTI’
> ./linux/if.h:100:23: error: redeclaration of enumerator ‘IFF_PROMISC’
>
> The cases where linux/if.h is included before net/if.h need a similar fix in
> the glibc side, or the order of include files can be changed userspace
> code as a workaround.
>
> This change was tested in x86 userspace on Debian unstable with
> scripts/headers_compile_test.sh:
>
> $ make headers_install && \
>   cd usr/include && ../../scripts/headers_compile_test.sh -l -k
> ...
> cc -Wall -c -nostdinc -I /usr/lib/gcc/i586-linux-gnu/5/include -I /usr/lib/gcc/i586-linux-gnu/5/include-fixed -I . -I /home/mcfrisk/src/linux-2.6/usr/headers_compile_test_include.2uX2zH -I /home/mcfrisk/src/linux-2.6/usr/headers_compile_test_include.2uX2zH/i586-linux-gnu -o /dev/null ./linux/if.h_libc_before_kernel.h
> PASSED libc before kernel test: ./linux/if.h
>
> Reported-by: Jan Engelhardt <jengelh@inai.de>
> Reported-by: Josh Boyer <jwboyer@fedoraproject.org>
> Reported-by: Stephen Hemminger <shemming@brocade.com>
> Reported-by: Waldemar Brodkorb <mail@waldemar-brodkorb.de>
> Cc: Gabriel Laskar <gabriel@lse.epita.fr>
> Signed-off-by: Mikko Rapeli <mikko.rapeli@iki.fi>

Bump.  Did this get lost in a queue somewhere?

josh

> ---
>  include/uapi/linux/if.h          | 28 +++++++++++++++++++++++++
>  include/uapi/linux/libc-compat.h | 44 ++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 72 insertions(+)
>
> v1:
> http://marc.info/?l=linux-kernel&m=145485386721798&w=2
>
> v2:
> Added handling for net_device_flags IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO
> which are unknown to glibc as suggested by David Miller in
> http://marc.info/?l=linux-kernel&m=145650410726228&w=2
>
> diff --git a/include/uapi/linux/if.h b/include/uapi/linux/if.h
> index f802775..e601c8c 100644
> --- a/include/uapi/linux/if.h
> +++ b/include/uapi/linux/if.h
> @@ -19,14 +19,20 @@
>  #ifndef _LINUX_IF_H
>  #define _LINUX_IF_H
>
> +#include <linux/libc-compat.h>          /* for compatibility with glibc */
>  #include <linux/types.h>               /* for "__kernel_caddr_t" et al */
>  #include <linux/socket.h>              /* for "struct sockaddr" et al  */
>  #include <linux/compiler.h>            /* for "__user" et al           */
>
> +#if __UAPI_DEF_IF_IFNAMSIZ
>  #define        IFNAMSIZ        16
> +#endif /* __UAPI_DEF_IF_IFNAMSIZ */
>  #define        IFALIASZ        256
>  #include <linux/hdlc/ioctl.h>
>
> +/* For glibc compatibility. An empty enum does not compile. */
> +#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 && \
> +    __UAPI_DEF_IF_NET_DEVICE_FLAGS != 0
>  /**
>   * enum net_device_flags - &struct net_device flags
>   *
> @@ -68,6 +74,8 @@
>   * @IFF_ECHO: echo sent packets. Volatile.
>   */
>  enum net_device_flags {
> +/* for compatibility with glibc net/if.h */
> +#if __UAPI_DEF_IF_NET_DEVICE_FLAGS
>         IFF_UP                          = 1<<0,  /* sysfs */
>         IFF_BROADCAST                   = 1<<1,  /* volatile */
>         IFF_DEBUG                       = 1<<2,  /* sysfs */
> @@ -84,11 +92,17 @@ enum net_device_flags {
>         IFF_PORTSEL                     = 1<<13, /* sysfs */
>         IFF_AUTOMEDIA                   = 1<<14, /* sysfs */
>         IFF_DYNAMIC                     = 1<<15, /* sysfs */
> +#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS */
> +#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO
>         IFF_LOWER_UP                    = 1<<16, /* volatile */
>         IFF_DORMANT                     = 1<<17, /* volatile */
>         IFF_ECHO                        = 1<<18, /* volatile */
> +#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */
>  };
> +#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 && __UAPI_DEF_IF_NET_DEVICE_FLAGS != 0 */
>
> +/* for compatibility with glibc net/if.h */
> +#if __UAPI_DEF_IF_NET_DEVICE_FLAGS
>  #define IFF_UP                         IFF_UP
>  #define IFF_BROADCAST                  IFF_BROADCAST
>  #define IFF_DEBUG                      IFF_DEBUG
> @@ -105,9 +119,13 @@ enum net_device_flags {
>  #define IFF_PORTSEL                    IFF_PORTSEL
>  #define IFF_AUTOMEDIA                  IFF_AUTOMEDIA
>  #define IFF_DYNAMIC                    IFF_DYNAMIC
> +#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS */
> +
> +#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO
>  #define IFF_LOWER_UP                   IFF_LOWER_UP
>  #define IFF_DORMANT                    IFF_DORMANT
>  #define IFF_ECHO                       IFF_ECHO
> +#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */
>
>  #define IFF_VOLATILE   (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_ECHO|\
>                 IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT)
> @@ -166,6 +184,8 @@ enum {
>   *     being very small might be worth keeping for clean configuration.
>   */
>
> +/* for compatibility with glibc net/if.h */
> +#if __UAPI_DEF_IF_IFMAP
>  struct ifmap {
>         unsigned long mem_start;
>         unsigned long mem_end;
> @@ -175,6 +195,7 @@ struct ifmap {
>         unsigned char port;
>         /* 3 bytes spare */
>  };
> +#endif /* __UAPI_DEF_IF_IFMAP */
>
>  struct if_settings {
>         unsigned int type;      /* Type of physical device or protocol */
> @@ -200,6 +221,8 @@ struct if_settings {
>   * remainder may be interface specific.
>   */
>
> +/* for compatibility with glibc net/if.h */
> +#if __UAPI_DEF_IF_IFREQ
>  struct ifreq {
>  #define IFHWADDRLEN    6
>         union
> @@ -223,6 +246,7 @@ struct ifreq {
>                 struct  if_settings ifru_settings;
>         } ifr_ifru;
>  };
> +#endif /* __UAPI_DEF_IF_IFREQ */
>
>  #define ifr_name       ifr_ifrn.ifrn_name      /* interface name       */
>  #define ifr_hwaddr     ifr_ifru.ifru_hwaddr    /* MAC address          */
> @@ -249,6 +273,8 @@ struct ifreq {
>   * must know all networks accessible).
>   */
>
> +/* for compatibility with glibc net/if.h */
> +#if __UAPI_DEF_IF_IFCONF
>  struct ifconf  {
>         int     ifc_len;                        /* size of buffer       */
>         union {
> @@ -256,6 +282,8 @@ struct ifconf  {
>                 struct ifreq __user *ifcu_req;
>         } ifc_ifcu;
>  };
> +#endif /* __UAPI_DEF_IF_IFCONF */
> +
>  #define        ifc_buf ifc_ifcu.ifcu_buf               /* buffer address       */
>  #define        ifc_req ifc_ifcu.ifcu_req               /* array of structures  */
>
> diff --git a/include/uapi/linux/libc-compat.h b/include/uapi/linux/libc-compat.h
> index 7d024ce..d5e38c7 100644
> --- a/include/uapi/linux/libc-compat.h
> +++ b/include/uapi/linux/libc-compat.h
> @@ -51,6 +51,40 @@
>  /* We have included glibc headers... */
>  #if defined(__GLIBC__)
>
> +/* Coordinate with glibc net/if.h header. */
> +#if defined(_NET_IF_H)
> +
> +/* GLIBC headers included first so don't define anything
> + * that would already be defined. */
> +
> +#define __UAPI_DEF_IF_IFCONF 0
> +#define __UAPI_DEF_IF_IFMAP 0
> +#define __UAPI_DEF_IF_IFNAMSIZ 0
> +#define __UAPI_DEF_IF_IFREQ 0
> +/* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */
> +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 0
> +/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */
> +#ifndef __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO
> +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1
> +#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */
> +
> +#else /* _NET_IF_H */
> +
> +/* Linux headers included first, and we must define everything
> + * we need. The expectation is that glibc will check the
> + * __UAPI_DEF_* defines and adjust appropriately. */
> +
> +#define __UAPI_DEF_IF_IFCONF 1
> +#define __UAPI_DEF_IF_IFMAP 1
> +#define __UAPI_DEF_IF_IFNAMSIZ 1
> +#define __UAPI_DEF_IF_IFREQ 1
> +/* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */
> +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 1
> +/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */
> +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1
> +
> +#endif /* _NET_IF_H */
> +
>  /* Coordinate with glibc netinet/in.h header. */
>  #if defined(_NETINET_IN_H)
>
> @@ -117,6 +151,16 @@
>   * that we need. */
>  #else /* !defined(__GLIBC__) */
>
> +/* Definitions for if.h */
> +#define __UAPI_DEF_IF_IFCONF 1
> +#define __UAPI_DEF_IF_IFMAP 1
> +#define __UAPI_DEF_IF_IFNAMSIZ 1
> +#define __UAPI_DEF_IF_IFREQ 1
> +/* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */
> +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 1
> +/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */
> +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1
> +
>  /* Definitions for in.h */
>  #define __UAPI_DEF_IN_ADDR             1
>  #define __UAPI_DEF_IN_IPPROTO          1
> --
> 2.8.0.rc3
>
  
Pablo Neira Ayuso May 9, 2016, 9:35 p.m. UTC | #4
On Mon, May 09, 2016 at 09:59:22AM -0400, Josh Boyer wrote:
> On Sun, Apr 24, 2016 at 11:45 AM, Mikko Rapeli <mikko.rapeli@iki.fi> wrote:
> > glibc's net/if.h contains copies of definitions from linux/if.h and these
> > conflict and cause build failures if both files are included by application
> > source code. Changes in uapi headers, which fixed header file dependencies to
> > include linux/if.h when it was needed, e.g. commit 1ffad83d, made the
> > net/if.h and linux/if.h incompatibilities visible as build failures for
> > userspace applications like iproute2 and xtables-addons.
> >
> > This patch fixes compile errors when glibc net/if.h is included before
> > linux/if.h:
> >
> > ./linux/if.h:99:21: error: redeclaration of enumerator ‘IFF_NOARP’
[...]
> >
> > The cases where linux/if.h is included before net/if.h need a similar fix in
> > the glibc side, or the order of include files can be changed userspace
> > code as a workaround.
> >
> > This change was tested in x86 userspace on Debian unstable with
> > scripts/headers_compile_test.sh:
> >
> > $ make headers_install && \
> >   cd usr/include && ../../scripts/headers_compile_test.sh -l -k
> > ...
> > cc -Wall -c -nostdinc -I /usr/lib/gcc/i586-linux-gnu/5/include -I /usr/lib/gcc/i586-linux-gnu/5/include-fixed -I . -I /home/mcfrisk/src/linux-2.6/usr/headers_compile_test_include.2uX2zH -I /home/mcfrisk/src/linux-2.6/usr/headers_compile_test_include.2uX2zH/i586-linux-gnu -o /dev/null ./linux/if.h_libc_before_kernel.h
> > PASSED libc before kernel test: ./linux/if.h
> >
> > Reported-by: Jan Engelhardt <jengelh@inai.de>
> > Reported-by: Josh Boyer <jwboyer@fedoraproject.org>
> > Reported-by: Stephen Hemminger <shemming@brocade.com>
> > Reported-by: Waldemar Brodkorb <mail@waldemar-brodkorb.de>
> > Cc: Gabriel Laskar <gabriel@lse.epita.fr>
> > Signed-off-by: Mikko Rapeli <mikko.rapeli@iki.fi>
> 
> Bump.  Did this get lost in a queue somewhere?

It seems linux-netdev was not Cc'ed. I cannot find this in David's
patchwork [1].

@Mikko: Could you resubmit including netdev@vger.kernel.org? Thanks.

[1] http://patchwork.ozlabs.org/project/netdev/list/.
  
Mikko Rapeli May 9, 2016, 10:15 p.m. UTC | #5
On Mon, May 09, 2016 at 11:35:35PM +0200, Pablo Neira Ayuso wrote:
> It seems linux-netdev was not Cc'ed. I cannot find this in David's
> patchwork [1].
> 
> @Mikko: Could you resubmit including netdev@vger.kernel.org? Thanks.

Done: http://patchwork.ozlabs.org/patch/620262/

-Mikko
  
David Miller May 10, 2016, 1:29 a.m. UTC | #6
From: Mikko Rapeli <mikko.rapeli@iki.fi>

Date: Sun, 24 Apr 2016 17:45:00 +0200

> glibc's net/if.h contains copies of definitions from linux/if.h and these

> conflict and cause build failures if both files are included by application

> source code. Changes in uapi headers, which fixed header file dependencies to

> include linux/if.h when it was needed, e.g. commit 1ffad83d, made the

> net/if.h and linux/if.h incompatibilities visible as build failures for

> userspace applications like iproute2 and xtables-addons.

> 

> This patch fixes compile errors when glibc net/if.h is included before

> linux/if.h:

> 

> ./linux/if.h:99:21: error: redeclaration of enumerator ‘IFF_NOARP’

> ./linux/if.h:98:23: error: redeclaration of enumerator ‘IFF_RUNNING’

> ./linux/if.h:97:26: error: redeclaration of enumerator ‘IFF_NOTRAILERS’

> ./linux/if.h:96:27: error: redeclaration of enumerator ‘IFF_POINTOPOINT’

> ./linux/if.h:95:24: error: redeclaration of enumerator ‘IFF_LOOPBACK’

> ./linux/if.h:94:21: error: redeclaration of enumerator ‘IFF_DEBUG’

> ./linux/if.h:93:25: error: redeclaration of enumerator ‘IFF_BROADCAST’

> ./linux/if.h:92:19: error: redeclaration of enumerator ‘IFF_UP’

> ./linux/if.h:252:8: error: redefinition of ‘struct ifconf’

> ./linux/if.h:203:8: error: redefinition of ‘struct ifreq’

> ./linux/if.h:169:8: error: redefinition of ‘struct ifmap’

> ./linux/if.h:107:23: error: redeclaration of enumerator ‘IFF_DYNAMIC’

> ./linux/if.h:106:25: error: redeclaration of enumerator ‘IFF_AUTOMEDIA’

> ./linux/if.h:105:23: error: redeclaration of enumerator ‘IFF_PORTSEL’

> ./linux/if.h:104:25: error: redeclaration of enumerator ‘IFF_MULTICAST’

> ./linux/if.h:103:21: error: redeclaration of enumerator ‘IFF_SLAVE’

> ./linux/if.h:102:22: error: redeclaration of enumerator ‘IFF_MASTER’

> ./linux/if.h:101:24: error: redeclaration of enumerator ‘IFF_ALLMULTI’

> ./linux/if.h:100:23: error: redeclaration of enumerator ‘IFF_PROMISC’

> 

> The cases where linux/if.h is included before net/if.h need a similar fix in

> the glibc side, or the order of include files can be changed userspace

> code as a workaround.

> 

> This change was tested in x86 userspace on Debian unstable with

> scripts/headers_compile_test.sh:

> 

> $ make headers_install && \

>   cd usr/include && ../../scripts/headers_compile_test.sh -l -k

> ...

> cc -Wall -c -nostdinc -I /usr/lib/gcc/i586-linux-gnu/5/include -I /usr/lib/gcc/i586-linux-gnu/5/include-fixed -I . -I /home/mcfrisk/src/linux-2.6/usr/headers_compile_test_include.2uX2zH -I /home/mcfrisk/src/linux-2.6/usr/headers_compile_test_include.2uX2zH/i586-linux-gnu -o /dev/null ./linux/if.h_libc_before_kernel.h

> PASSED libc before kernel test: ./linux/if.h

> 

> Reported-by: Jan Engelhardt <jengelh@inai.de>

> Reported-by: Josh Boyer <jwboyer@fedoraproject.org>

> Reported-by: Stephen Hemminger <shemming@brocade.com>

> Reported-by: Waldemar Brodkorb <mail@waldemar-brodkorb.de>

> Cc: Gabriel Laskar <gabriel@lse.epita.fr>

> Signed-off-by: Mikko Rapeli <mikko.rapeli@iki.fi>


Applied and queued up for -stable, t hanks.
  

Patch

diff --git a/include/uapi/linux/if.h b/include/uapi/linux/if.h
index f802775..e601c8c 100644
--- a/include/uapi/linux/if.h
+++ b/include/uapi/linux/if.h
@@ -19,14 +19,20 @@ 
 #ifndef _LINUX_IF_H
 #define _LINUX_IF_H
 
+#include <linux/libc-compat.h>          /* for compatibility with glibc */
 #include <linux/types.h>		/* for "__kernel_caddr_t" et al	*/
 #include <linux/socket.h>		/* for "struct sockaddr" et al	*/
 #include <linux/compiler.h>		/* for "__user" et al           */
 
+#if __UAPI_DEF_IF_IFNAMSIZ
 #define	IFNAMSIZ	16
+#endif /* __UAPI_DEF_IF_IFNAMSIZ */
 #define	IFALIASZ	256
 #include <linux/hdlc/ioctl.h>
 
+/* For glibc compatibility. An empty enum does not compile. */
+#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 && \
+    __UAPI_DEF_IF_NET_DEVICE_FLAGS != 0
 /**
  * enum net_device_flags - &struct net_device flags
  *
@@ -68,6 +74,8 @@ 
  * @IFF_ECHO: echo sent packets. Volatile.
  */
 enum net_device_flags {
+/* for compatibility with glibc net/if.h */
+#if __UAPI_DEF_IF_NET_DEVICE_FLAGS
 	IFF_UP				= 1<<0,  /* sysfs */
 	IFF_BROADCAST			= 1<<1,  /* volatile */
 	IFF_DEBUG			= 1<<2,  /* sysfs */
@@ -84,11 +92,17 @@  enum net_device_flags {
 	IFF_PORTSEL			= 1<<13, /* sysfs */
 	IFF_AUTOMEDIA			= 1<<14, /* sysfs */
 	IFF_DYNAMIC			= 1<<15, /* sysfs */
+#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS */
+#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO
 	IFF_LOWER_UP			= 1<<16, /* volatile */
 	IFF_DORMANT			= 1<<17, /* volatile */
 	IFF_ECHO			= 1<<18, /* volatile */
+#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */
 };
+#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 && __UAPI_DEF_IF_NET_DEVICE_FLAGS != 0 */
 
+/* for compatibility with glibc net/if.h */
+#if __UAPI_DEF_IF_NET_DEVICE_FLAGS
 #define IFF_UP				IFF_UP
 #define IFF_BROADCAST			IFF_BROADCAST
 #define IFF_DEBUG			IFF_DEBUG
@@ -105,9 +119,13 @@  enum net_device_flags {
 #define IFF_PORTSEL			IFF_PORTSEL
 #define IFF_AUTOMEDIA			IFF_AUTOMEDIA
 #define IFF_DYNAMIC			IFF_DYNAMIC
+#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS */
+
+#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO
 #define IFF_LOWER_UP			IFF_LOWER_UP
 #define IFF_DORMANT			IFF_DORMANT
 #define IFF_ECHO			IFF_ECHO
+#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */
 
 #define IFF_VOLATILE	(IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_ECHO|\
 		IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT)
@@ -166,6 +184,8 @@  enum {
  *	being very small might be worth keeping for clean configuration.
  */
 
+/* for compatibility with glibc net/if.h */
+#if __UAPI_DEF_IF_IFMAP
 struct ifmap {
 	unsigned long mem_start;
 	unsigned long mem_end;
@@ -175,6 +195,7 @@  struct ifmap {
 	unsigned char port;
 	/* 3 bytes spare */
 };
+#endif /* __UAPI_DEF_IF_IFMAP */
 
 struct if_settings {
 	unsigned int type;	/* Type of physical device or protocol */
@@ -200,6 +221,8 @@  struct if_settings {
  * remainder may be interface specific.
  */
 
+/* for compatibility with glibc net/if.h */
+#if __UAPI_DEF_IF_IFREQ
 struct ifreq {
 #define IFHWADDRLEN	6
 	union
@@ -223,6 +246,7 @@  struct ifreq {
 		struct	if_settings ifru_settings;
 	} ifr_ifru;
 };
+#endif /* __UAPI_DEF_IF_IFREQ */
 
 #define ifr_name	ifr_ifrn.ifrn_name	/* interface name 	*/
 #define ifr_hwaddr	ifr_ifru.ifru_hwaddr	/* MAC address 		*/
@@ -249,6 +273,8 @@  struct ifreq {
  * must know all networks accessible).
  */
 
+/* for compatibility with glibc net/if.h */
+#if __UAPI_DEF_IF_IFCONF
 struct ifconf  {
 	int	ifc_len;			/* size of buffer	*/
 	union {
@@ -256,6 +282,8 @@  struct ifconf  {
 		struct ifreq __user *ifcu_req;
 	} ifc_ifcu;
 };
+#endif /* __UAPI_DEF_IF_IFCONF */
+
 #define	ifc_buf	ifc_ifcu.ifcu_buf		/* buffer address	*/
 #define	ifc_req	ifc_ifcu.ifcu_req		/* array of structures	*/
 
diff --git a/include/uapi/linux/libc-compat.h b/include/uapi/linux/libc-compat.h
index 7d024ce..d5e38c7 100644
--- a/include/uapi/linux/libc-compat.h
+++ b/include/uapi/linux/libc-compat.h
@@ -51,6 +51,40 @@ 
 /* We have included glibc headers... */
 #if defined(__GLIBC__)
 
+/* Coordinate with glibc net/if.h header. */
+#if defined(_NET_IF_H)
+
+/* GLIBC headers included first so don't define anything
+ * that would already be defined. */
+
+#define __UAPI_DEF_IF_IFCONF 0
+#define __UAPI_DEF_IF_IFMAP 0
+#define __UAPI_DEF_IF_IFNAMSIZ 0
+#define __UAPI_DEF_IF_IFREQ 0
+/* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */
+#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 0
+/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */
+#ifndef __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO
+#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1
+#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */
+
+#else /* _NET_IF_H */
+
+/* Linux headers included first, and we must define everything
+ * we need. The expectation is that glibc will check the
+ * __UAPI_DEF_* defines and adjust appropriately. */
+
+#define __UAPI_DEF_IF_IFCONF 1
+#define __UAPI_DEF_IF_IFMAP 1
+#define __UAPI_DEF_IF_IFNAMSIZ 1
+#define __UAPI_DEF_IF_IFREQ 1
+/* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */
+#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 1
+/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */
+#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1
+
+#endif /* _NET_IF_H */
+
 /* Coordinate with glibc netinet/in.h header. */
 #if defined(_NETINET_IN_H)
 
@@ -117,6 +151,16 @@ 
  * that we need. */
 #else /* !defined(__GLIBC__) */
 
+/* Definitions for if.h */
+#define __UAPI_DEF_IF_IFCONF 1
+#define __UAPI_DEF_IF_IFMAP 1
+#define __UAPI_DEF_IF_IFNAMSIZ 1
+#define __UAPI_DEF_IF_IFREQ 1
+/* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */
+#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 1
+/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */
+#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1
+
 /* Definitions for in.h */
 #define __UAPI_DEF_IN_ADDR		1
 #define __UAPI_DEF_IN_IPPROTO		1