diff options
author | Thomas Haller <thaller@redhat.com> | 2015-12-07 11:21:16 (GMT) |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2015-12-07 11:23:51 (GMT) |
commit | 6555b0df89b1a99cfc32431600cd0a83345274ab (patch) | |
tree | aaf0dc93e46d7a120f13ddf42c04f529e7fb7b63 | |
parent | 7bbd09d9410f5fc0d22f00db26306234a50217a2 (diff) | |
parent | 1f914c892a71ceaaedc1a77f7659849b7a79bca4 (diff) | |
download | libnl-6555b0df89b1a99cfc32431600cd0a83345274ab.zip libnl-6555b0df89b1a99cfc32431600cd0a83345274ab.tar.gz libnl-6555b0df89b1a99cfc32431600cd0a83345274ab.tar.bz2 |
route/bridge: merge branch 'bridge-vlan'
Add support for vlan attributes for bridges.
http://lists.infradead.org/pipermail/libnl/2015-November/002032.html
http://lists.infradead.org/pipermail/libnl/2015-November/002047.html
Signed-off-by: Thomas Haller <thaller@redhat.com>
-rw-r--r-- | include/linux-private/linux/if_bridge.h | 25 | ||||
-rw-r--r-- | include/linux-private/linux/in.h | 299 | ||||
-rw-r--r-- | include/linux-private/linux/in6.h | 293 | ||||
-rw-r--r-- | include/linux-private/linux/libc-compat.h | 143 | ||||
-rw-r--r-- | include/linux-private/linux/rtnetlink.h | 83 | ||||
-rw-r--r-- | include/netlink-private/route/link/api.h | 9 | ||||
-rw-r--r-- | include/netlink/route/link/bridge.h | 15 | ||||
-rw-r--r-- | lib/route/link.c | 67 | ||||
-rw-r--r-- | lib/route/link/bridge.c | 218 | ||||
-rw-r--r-- | lib/route/neigh.c | 9 | ||||
-rw-r--r-- | libnl-route-3.sym | 3 |
11 files changed, 1136 insertions, 28 deletions
diff --git a/include/linux-private/linux/if_bridge.h b/include/linux-private/linux/if_bridge.h index 5db2975..f24050b 100644 --- a/include/linux-private/linux/if_bridge.h +++ b/include/linux-private/linux/if_bridge.h @@ -10,10 +10,12 @@ * 2 of the License, or (at your option) any later version. */ -#ifndef _UAPI_LINUX_IF_BRIDGE_H -#define _UAPI_LINUX_IF_BRIDGE_H +#ifndef _LINUX_IF_BRIDGE_H +#define _LINUX_IF_BRIDGE_H #include <linux/types.h> +#include <linux/if_ether.h> +#include <linux/in6.h> #define SYSFS_BRIDGE_ATTR "bridge" #define SYSFS_BRIDGE_FDB "brforward" @@ -88,7 +90,7 @@ struct __port_info { }; struct __fdb_entry { - __u8 mac_addr[6]; + __u8 mac_addr[ETH_ALEN]; __u8 port_no; __u8 is_local; __u32 ageing_timer_value; @@ -103,20 +105,34 @@ struct __fdb_entry { #define BRIDGE_MODE_VEB 0 /* Default loopback mode */ #define BRIDGE_MODE_VEPA 1 /* 802.1Qbg defined VEPA mode */ +#define BRIDGE_MODE_UNDEF 0xFFFF /* mode undefined */ /* Bridge management nested attributes * [IFLA_AF_SPEC] = { * [IFLA_BRIDGE_FLAGS] * [IFLA_BRIDGE_MODE] + * [IFLA_BRIDGE_VLAN_INFO] * } */ enum { IFLA_BRIDGE_FLAGS, IFLA_BRIDGE_MODE, + IFLA_BRIDGE_VLAN_INFO, __IFLA_BRIDGE_MAX, }; #define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1) +#define BRIDGE_VLAN_INFO_MASTER (1<<0) /* Operate on Bridge device as well */ +#define BRIDGE_VLAN_INFO_PVID (1<<1) /* VLAN is PVID, ingress untagged */ +#define BRIDGE_VLAN_INFO_UNTAGGED (1<<2) /* VLAN egresses untagged */ +#define BRIDGE_VLAN_INFO_RANGE_BEGIN (1<<3) /* VLAN is start of vlan range */ +#define BRIDGE_VLAN_INFO_RANGE_END (1<<4) /* VLAN is end of vlan range */ + +struct bridge_vlan_info { + __u16 flags; + __u16 vid; +}; + /* Bridge multicast database attributes * [MDBA_MDB] = { * [MDBA_MDB_ENTRY] = { @@ -166,6 +182,7 @@ struct br_mdb_entry { #define MDB_TEMPORARY 0 #define MDB_PERMANENT 1 __u8 state; + __u16 vid; struct { union { __be32 ip4; @@ -182,4 +199,4 @@ enum { }; #define MDBA_SET_ENTRY_MAX (__MDBA_SET_ENTRY_MAX - 1) -#endif /* _UAPI_LINUX_IF_BRIDGE_H */ +#endif /* _LINUX_IF_BRIDGE_H */ diff --git a/include/linux-private/linux/in.h b/include/linux-private/linux/in.h new file mode 100644 index 0000000..194b43b --- /dev/null +++ b/include/linux-private/linux/in.h @@ -0,0 +1,299 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions of the Internet Protocol. + * + * Version: @(#)in.h 1.0.1 04/21/93 + * + * Authors: Original taken from the GNU Project <netinet/in.h> file. + * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _LINUX_IN_H +#define _LINUX_IN_H + +#include <linux/types.h> +#include <linux/libc-compat.h> +#include <linux/socket.h> + +#if __UAPI_DEF_IN_IPPROTO +/* Standard well-defined IP protocols. */ +enum { + IPPROTO_IP = 0, /* Dummy protocol for TCP */ +#define IPPROTO_IP IPPROTO_IP + IPPROTO_ICMP = 1, /* Internet Control Message Protocol */ +#define IPPROTO_ICMP IPPROTO_ICMP + IPPROTO_IGMP = 2, /* Internet Group Management Protocol */ +#define IPPROTO_IGMP IPPROTO_IGMP + IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94) */ +#define IPPROTO_IPIP IPPROTO_IPIP + IPPROTO_TCP = 6, /* Transmission Control Protocol */ +#define IPPROTO_TCP IPPROTO_TCP + IPPROTO_EGP = 8, /* Exterior Gateway Protocol */ +#define IPPROTO_EGP IPPROTO_EGP + IPPROTO_PUP = 12, /* PUP protocol */ +#define IPPROTO_PUP IPPROTO_PUP + IPPROTO_UDP = 17, /* User Datagram Protocol */ +#define IPPROTO_UDP IPPROTO_UDP + IPPROTO_IDP = 22, /* XNS IDP protocol */ +#define IPPROTO_IDP IPPROTO_IDP + IPPROTO_TP = 29, /* SO Transport Protocol Class 4 */ +#define IPPROTO_TP IPPROTO_TP + IPPROTO_DCCP = 33, /* Datagram Congestion Control Protocol */ +#define IPPROTO_DCCP IPPROTO_DCCP + IPPROTO_IPV6 = 41, /* IPv6-in-IPv4 tunnelling */ +#define IPPROTO_IPV6 IPPROTO_IPV6 + IPPROTO_RSVP = 46, /* RSVP Protocol */ +#define IPPROTO_RSVP IPPROTO_RSVP + IPPROTO_GRE = 47, /* Cisco GRE tunnels (rfc 1701,1702) */ +#define IPPROTO_GRE IPPROTO_GRE + IPPROTO_ESP = 50, /* Encapsulation Security Payload protocol */ +#define IPPROTO_ESP IPPROTO_ESP + IPPROTO_AH = 51, /* Authentication Header protocol */ +#define IPPROTO_AH IPPROTO_AH + IPPROTO_MTP = 92, /* Multicast Transport Protocol */ +#define IPPROTO_MTP IPPROTO_MTP + IPPROTO_BEETPH = 94, /* IP option pseudo header for BEET */ +#define IPPROTO_BEETPH IPPROTO_BEETPH + IPPROTO_ENCAP = 98, /* Encapsulation Header */ +#define IPPROTO_ENCAP IPPROTO_ENCAP + IPPROTO_PIM = 103, /* Protocol Independent Multicast */ +#define IPPROTO_PIM IPPROTO_PIM + IPPROTO_COMP = 108, /* Compression Header Protocol */ +#define IPPROTO_COMP IPPROTO_COMP + IPPROTO_SCTP = 132, /* Stream Control Transport Protocol */ +#define IPPROTO_SCTP IPPROTO_SCTP + IPPROTO_UDPLITE = 136, /* UDP-Lite (RFC 3828) */ +#define IPPROTO_UDPLITE IPPROTO_UDPLITE + IPPROTO_MPLS = 137, /* MPLS in IP (RFC 4023) */ +#define IPPROTO_MPLS IPPROTO_MPLS + IPPROTO_RAW = 255, /* Raw IP packets */ +#define IPPROTO_RAW IPPROTO_RAW + IPPROTO_MAX +}; +#endif + +#if __UAPI_DEF_IN_ADDR +/* Internet address. */ +struct in_addr { + __be32 s_addr; +}; +#endif + +#define IP_TOS 1 +#define IP_TTL 2 +#define IP_HDRINCL 3 +#define IP_OPTIONS 4 +#define IP_ROUTER_ALERT 5 +#define IP_RECVOPTS 6 +#define IP_RETOPTS 7 +#define IP_PKTINFO 8 +#define IP_PKTOPTIONS 9 +#define IP_MTU_DISCOVER 10 +#define IP_RECVERR 11 +#define IP_RECVTTL 12 +#define IP_RECVTOS 13 +#define IP_MTU 14 +#define IP_FREEBIND 15 +#define IP_IPSEC_POLICY 16 +#define IP_XFRM_POLICY 17 +#define IP_PASSSEC 18 +#define IP_TRANSPARENT 19 + +/* BSD compatibility */ +#define IP_RECVRETOPTS IP_RETOPTS + +/* TProxy original addresses */ +#define IP_ORIGDSTADDR 20 +#define IP_RECVORIGDSTADDR IP_ORIGDSTADDR + +#define IP_MINTTL 21 +#define IP_NODEFRAG 22 +#define IP_CHECKSUM 23 +#define IP_BIND_ADDRESS_NO_PORT 24 + +/* IP_MTU_DISCOVER values */ +#define IP_PMTUDISC_DONT 0 /* Never send DF frames */ +#define IP_PMTUDISC_WANT 1 /* Use per route hints */ +#define IP_PMTUDISC_DO 2 /* Always DF */ +#define IP_PMTUDISC_PROBE 3 /* Ignore dst pmtu */ +/* Always use interface mtu (ignores dst pmtu) but don't set DF flag. + * Also incoming ICMP frag_needed notifications will be ignored on + * this socket to prevent accepting spoofed ones. + */ +#define IP_PMTUDISC_INTERFACE 4 +/* weaker version of IP_PMTUDISC_INTERFACE, which allos packets to get + * fragmented if they exeed the interface mtu + */ +#define IP_PMTUDISC_OMIT 5 + +#define IP_MULTICAST_IF 32 +#define IP_MULTICAST_TTL 33 +#define IP_MULTICAST_LOOP 34 +#define IP_ADD_MEMBERSHIP 35 +#define IP_DROP_MEMBERSHIP 36 +#define IP_UNBLOCK_SOURCE 37 +#define IP_BLOCK_SOURCE 38 +#define IP_ADD_SOURCE_MEMBERSHIP 39 +#define IP_DROP_SOURCE_MEMBERSHIP 40 +#define IP_MSFILTER 41 +#define MCAST_JOIN_GROUP 42 +#define MCAST_BLOCK_SOURCE 43 +#define MCAST_UNBLOCK_SOURCE 44 +#define MCAST_LEAVE_GROUP 45 +#define MCAST_JOIN_SOURCE_GROUP 46 +#define MCAST_LEAVE_SOURCE_GROUP 47 +#define MCAST_MSFILTER 48 +#define IP_MULTICAST_ALL 49 +#define IP_UNICAST_IF 50 + +#define MCAST_EXCLUDE 0 +#define MCAST_INCLUDE 1 + +/* These need to appear somewhere around here */ +#define IP_DEFAULT_MULTICAST_TTL 1 +#define IP_DEFAULT_MULTICAST_LOOP 1 + +/* Request struct for multicast socket ops */ + +#if __UAPI_DEF_IP_MREQ +struct ip_mreq { + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_interface; /* local IP address of interface */ +}; + +struct ip_mreqn { + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_address; /* local IP address of interface */ + int imr_ifindex; /* Interface index */ +}; + +struct ip_mreq_source { + __be32 imr_multiaddr; + __be32 imr_interface; + __be32 imr_sourceaddr; +}; + +struct ip_msfilter { + __be32 imsf_multiaddr; + __be32 imsf_interface; + __u32 imsf_fmode; + __u32 imsf_numsrc; + __be32 imsf_slist[1]; +}; + +#define IP_MSFILTER_SIZE(numsrc) \ + (sizeof(struct ip_msfilter) - sizeof(__u32) \ + + (numsrc) * sizeof(__u32)) + +struct group_req { + __u32 gr_interface; /* interface index */ + struct __kernel_sockaddr_storage gr_group; /* group address */ +}; + +struct group_source_req { + __u32 gsr_interface; /* interface index */ + struct __kernel_sockaddr_storage gsr_group; /* group address */ + struct __kernel_sockaddr_storage gsr_source; /* source address */ +}; + +struct group_filter { + __u32 gf_interface; /* interface index */ + struct __kernel_sockaddr_storage gf_group; /* multicast address */ + __u32 gf_fmode; /* filter mode */ + __u32 gf_numsrc; /* number of sources */ + struct __kernel_sockaddr_storage gf_slist[1]; /* interface index */ +}; + +#define GROUP_FILTER_SIZE(numsrc) \ + (sizeof(struct group_filter) - sizeof(struct __kernel_sockaddr_storage) \ + + (numsrc) * sizeof(struct __kernel_sockaddr_storage)) +#endif + +#if __UAPI_DEF_IN_PKTINFO +struct in_pktinfo { + int ipi_ifindex; + struct in_addr ipi_spec_dst; + struct in_addr ipi_addr; +}; +#endif + +/* Structure describing an Internet (IP) socket address. */ +#if __UAPI_DEF_SOCKADDR_IN +#define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */ +struct sockaddr_in { + __kernel_sa_family_t sin_family; /* Address family */ + __be16 sin_port; /* Port number */ + struct in_addr sin_addr; /* Internet address */ + + /* Pad to size of `struct sockaddr'. */ + unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) - + sizeof(unsigned short int) - sizeof(struct in_addr)]; +}; +#define sin_zero __pad /* for BSD UNIX comp. -FvK */ +#endif + +#if __UAPI_DEF_IN_CLASS +/* + * Definitions of the bits in an Internet address integer. + * On subnets, host and network parts are found according + * to the subnet mask, not these masks. + */ +#define IN_CLASSA(a) ((((long int) (a)) & 0x80000000) == 0) +#define IN_CLASSA_NET 0xff000000 +#define IN_CLASSA_NSHIFT 24 +#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET) +#define IN_CLASSA_MAX 128 + +#define IN_CLASSB(a) ((((long int) (a)) & 0xc0000000) == 0x80000000) +#define IN_CLASSB_NET 0xffff0000 +#define IN_CLASSB_NSHIFT 16 +#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET) +#define IN_CLASSB_MAX 65536 + +#define IN_CLASSC(a) ((((long int) (a)) & 0xe0000000) == 0xc0000000) +#define IN_CLASSC_NET 0xffffff00 +#define IN_CLASSC_NSHIFT 8 +#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET) + +#define IN_CLASSD(a) ((((long int) (a)) & 0xf0000000) == 0xe0000000) +#define IN_MULTICAST(a) IN_CLASSD(a) +#define IN_MULTICAST_NET 0xF0000000 + +#define IN_EXPERIMENTAL(a) ((((long int) (a)) & 0xf0000000) == 0xf0000000) +#define IN_BADCLASS(a) IN_EXPERIMENTAL((a)) + +/* Address to accept any incoming messages. */ +#define INADDR_ANY ((unsigned long int) 0x00000000) + +/* Address to send to all hosts. */ +#define INADDR_BROADCAST ((unsigned long int) 0xffffffff) + +/* Address indicating an error return. */ +#define INADDR_NONE ((unsigned long int) 0xffffffff) + +/* Network number for local host loopback. */ +#define IN_LOOPBACKNET 127 + +/* Address to loopback in software to local host. */ +#define INADDR_LOOPBACK 0x7f000001 /* 127.0.0.1 */ +#define IN_LOOPBACK(a) ((((long int) (a)) & 0xff000000) == 0x7f000000) + +/* Defines for Multicast INADDR */ +#define INADDR_UNSPEC_GROUP 0xe0000000U /* 224.0.0.0 */ +#define INADDR_ALLHOSTS_GROUP 0xe0000001U /* 224.0.0.1 */ +#define INADDR_ALLRTRS_GROUP 0xe0000002U /* 224.0.0.2 */ +#define INADDR_MAX_LOCAL_GROUP 0xe00000ffU /* 224.0.0.255 */ +#endif + +/* <asm/byteorder.h> contains the htonl type stuff.. */ +#include <asm/byteorder.h> + + +#endif /* _LINUX_IN_H */ diff --git a/include/linux-private/linux/in6.h b/include/linux-private/linux/in6.h new file mode 100644 index 0000000..994f4c2 --- /dev/null +++ b/include/linux-private/linux/in6.h @@ -0,0 +1,293 @@ +/* + * Types and definitions for AF_INET6 + * Linux INET6 implementation + * + * Authors: + * Pedro Roque <roque@di.fc.ul.pt> + * + * Sources: + * IPv6 Program Interfaces for BSD Systems + * <draft-ietf-ipngwg-bsd-api-05.txt> + * + * Advanced Sockets API for IPv6 + * <draft-stevens-advanced-api-00.txt> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _LINUX_IN6_H +#define _LINUX_IN6_H + +#include <linux/types.h> +#include <linux/libc-compat.h> + +/* + * IPv6 address structure + */ + +#if __UAPI_DEF_IN6_ADDR +struct in6_addr { + union { + __u8 u6_addr8[16]; +#if __UAPI_DEF_IN6_ADDR_ALT + __be16 u6_addr16[8]; + __be32 u6_addr32[4]; +#endif + } in6_u; +#define s6_addr in6_u.u6_addr8 +#if __UAPI_DEF_IN6_ADDR_ALT +#define s6_addr16 in6_u.u6_addr16 +#define s6_addr32 in6_u.u6_addr32 +#endif +}; +#endif /* __UAPI_DEF_IN6_ADDR */ + +#if __UAPI_DEF_SOCKADDR_IN6 +struct sockaddr_in6 { + unsigned short int sin6_family; /* AF_INET6 */ + __be16 sin6_port; /* Transport layer port # */ + __be32 sin6_flowinfo; /* IPv6 flow information */ + struct in6_addr sin6_addr; /* IPv6 address */ + __u32 sin6_scope_id; /* scope id (new in RFC2553) */ +}; +#endif /* __UAPI_DEF_SOCKADDR_IN6 */ + +#if __UAPI_DEF_IPV6_MREQ +struct ipv6_mreq { + /* IPv6 multicast address of group */ + struct in6_addr ipv6mr_multiaddr; + + /* local IPv6 address of interface */ + int ipv6mr_ifindex; +}; +#endif /* __UAPI_DEF_IVP6_MREQ */ + +#define ipv6mr_acaddr ipv6mr_multiaddr + +struct in6_flowlabel_req { + struct in6_addr flr_dst; + __be32 flr_label; + __u8 flr_action; + __u8 flr_share; + __u16 flr_flags; + __u16 flr_expires; + __u16 flr_linger; + __u32 __flr_pad; + /* Options in format of IPV6_PKTOPTIONS */ +}; + +#define IPV6_FL_A_GET 0 +#define IPV6_FL_A_PUT 1 +#define IPV6_FL_A_RENEW 2 + +#define IPV6_FL_F_CREATE 1 +#define IPV6_FL_F_EXCL 2 +#define IPV6_FL_F_REFLECT 4 +#define IPV6_FL_F_REMOTE 8 + +#define IPV6_FL_S_NONE 0 +#define IPV6_FL_S_EXCL 1 +#define IPV6_FL_S_PROCESS 2 +#define IPV6_FL_S_USER 3 +#define IPV6_FL_S_ANY 255 + + +/* + * Bitmask constant declarations to help applications select out the + * flow label and priority fields. + * + * Note that this are in host byte order while the flowinfo field of + * sockaddr_in6 is in network byte order. + */ + +#define IPV6_FLOWINFO_FLOWLABEL 0x000fffff +#define IPV6_FLOWINFO_PRIORITY 0x0ff00000 + +/* These definitions are obsolete */ +#define IPV6_PRIORITY_UNCHARACTERIZED 0x0000 +#define IPV6_PRIORITY_FILLER 0x0100 +#define IPV6_PRIORITY_UNATTENDED 0x0200 +#define IPV6_PRIORITY_RESERVED1 0x0300 +#define IPV6_PRIORITY_BULK 0x0400 +#define IPV6_PRIORITY_RESERVED2 0x0500 +#define IPV6_PRIORITY_INTERACTIVE 0x0600 +#define IPV6_PRIORITY_CONTROL 0x0700 +#define IPV6_PRIORITY_8 0x0800 +#define IPV6_PRIORITY_9 0x0900 +#define IPV6_PRIORITY_10 0x0a00 +#define IPV6_PRIORITY_11 0x0b00 +#define IPV6_PRIORITY_12 0x0c00 +#define IPV6_PRIORITY_13 0x0d00 +#define IPV6_PRIORITY_14 0x0e00 +#define IPV6_PRIORITY_15 0x0f00 + +/* + * IPV6 extension headers + */ +#if __UAPI_DEF_IPPROTO_V6 +#define IPPROTO_HOPOPTS 0 /* IPv6 hop-by-hop options */ +#define IPPROTO_ROUTING 43 /* IPv6 routing header */ +#define IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header */ +#define IPPROTO_ICMPV6 58 /* ICMPv6 */ +#define IPPROTO_NONE 59 /* IPv6 no next header */ +#define IPPROTO_DSTOPTS 60 /* IPv6 destination options */ +#define IPPROTO_MH 135 /* IPv6 mobility header */ +#endif /* __UAPI_DEF_IPPROTO_V6 */ + +/* + * IPv6 TLV options. + */ +#define IPV6_TLV_PAD1 0 +#define IPV6_TLV_PADN 1 +#define IPV6_TLV_ROUTERALERT 5 +#define IPV6_TLV_JUMBO 194 +#define IPV6_TLV_HAO 201 /* home address option */ + +/* + * IPV6 socket options + */ +#if __UAPI_DEF_IPV6_OPTIONS +#define IPV6_ADDRFORM 1 +#define IPV6_2292PKTINFO 2 +#define IPV6_2292HOPOPTS 3 +#define IPV6_2292DSTOPTS 4 +#define IPV6_2292RTHDR 5 +#define IPV6_2292PKTOPTIONS 6 +#define IPV6_CHECKSUM 7 +#define IPV6_2292HOPLIMIT 8 +#define IPV6_NEXTHOP 9 +#define IPV6_AUTHHDR 10 /* obsolete */ +#define IPV6_FLOWINFO 11 + +#define IPV6_UNICAST_HOPS 16 +#define IPV6_MULTICAST_IF 17 +#define IPV6_MULTICAST_HOPS 18 +#define IPV6_MULTICAST_LOOP 19 +#define IPV6_ADD_MEMBERSHIP 20 +#define IPV6_DROP_MEMBERSHIP 21 +#define IPV6_ROUTER_ALERT 22 +#define IPV6_MTU_DISCOVER 23 +#define IPV6_MTU 24 +#define IPV6_RECVERR 25 +#define IPV6_V6ONLY 26 +#define IPV6_JOIN_ANYCAST 27 +#define IPV6_LEAVE_ANYCAST 28 + +/* IPV6_MTU_DISCOVER values */ +#define IPV6_PMTUDISC_DONT 0 +#define IPV6_PMTUDISC_WANT 1 +#define IPV6_PMTUDISC_DO 2 +#define IPV6_PMTUDISC_PROBE 3 +/* same as IPV6_PMTUDISC_PROBE, provided for symetry with IPv4 + * also see comments on IP_PMTUDISC_INTERFACE + */ +#define IPV6_PMTUDISC_INTERFACE 4 +/* weaker version of IPV6_PMTUDISC_INTERFACE, which allows packets to + * get fragmented if they exceed the interface mtu + */ +#define IPV6_PMTUDISC_OMIT 5 + +/* Flowlabel */ +#define IPV6_FLOWLABEL_MGR 32 +#define IPV6_FLOWINFO_SEND 33 + +#define IPV6_IPSEC_POLICY 34 +#define IPV6_XFRM_POLICY 35 +#endif + +/* + * Multicast: + * Following socket options are shared between IPv4 and IPv6. + * + * MCAST_JOIN_GROUP 42 + * MCAST_BLOCK_SOURCE 43 + * MCAST_UNBLOCK_SOURCE 44 + * MCAST_LEAVE_GROUP 45 + * MCAST_JOIN_SOURCE_GROUP 46 + * MCAST_LEAVE_SOURCE_GROUP 47 + * MCAST_MSFILTER 48 + */ + +/* + * Advanced API (RFC3542) (1) + * + * Note: IPV6_RECVRTHDRDSTOPTS does not exist. see net/ipv6/datagram.c. + */ + +#define IPV6_RECVPKTINFO 49 +#define IPV6_PKTINFO 50 +#define IPV6_RECVHOPLIMIT 51 +#define IPV6_HOPLIMIT 52 +#define IPV6_RECVHOPOPTS 53 +#define IPV6_HOPOPTS 54 +#define IPV6_RTHDRDSTOPTS 55 +#define IPV6_RECVRTHDR 56 +#define IPV6_RTHDR 57 +#define IPV6_RECVDSTOPTS 58 +#define IPV6_DSTOPTS 59 +#define IPV6_RECVPATHMTU 60 +#define IPV6_PATHMTU 61 +#define IPV6_DONTFRAG 62 +#if 0 /* not yet */ +#define IPV6_USE_MIN_MTU 63 +#endif + +/* + * Netfilter (1) + * + * Following socket options are used in ip6_tables; + * see include/linux/netfilter_ipv6/ip6_tables.h. + * + * IP6T_SO_SET_REPLACE / IP6T_SO_GET_INFO 64 + * IP6T_SO_SET_ADD_COUNTERS / IP6T_SO_GET_ENTRIES 65 + */ + +/* + * Advanced API (RFC3542) (2) + */ +#define IPV6_RECVTCLASS 66 +#define IPV6_TCLASS 67 + +/* + * Netfilter (2) + * + * Following socket options are used in ip6_tables; + * see include/linux/netfilter_ipv6/ip6_tables.h. + * + * IP6T_SO_GET_REVISION_MATCH 68 + * IP6T_SO_GET_REVISION_TARGET 69 + * IP6T_SO_ORIGINAL_DST 80 + */ + +#define IPV6_AUTOFLOWLABEL 70 +/* RFC5014: Source address selection */ +#define IPV6_ADDR_PREFERENCES 72 + +#define IPV6_PREFER_SRC_TMP 0x0001 +#define IPV6_PREFER_SRC_PUBLIC 0x0002 +#define IPV6_PREFER_SRC_PUBTMP_DEFAULT 0x0100 +#define IPV6_PREFER_SRC_COA 0x0004 +#define IPV6_PREFER_SRC_HOME 0x0400 +#define IPV6_PREFER_SRC_CGA 0x0008 +#define IPV6_PREFER_SRC_NONCGA 0x0800 + +/* RFC5082: Generalized Ttl Security Mechanism */ +#define IPV6_MINHOPCOUNT 73 + +#define IPV6_ORIGDSTADDR 74 +#define IPV6_RECVORIGDSTADDR IPV6_ORIGDSTADDR +#define IPV6_TRANSPARENT 75 +#define IPV6_UNICAST_IF 76 + +/* + * Multicast Routing: + * see include/uapi/linux/mroute6.h. + * + * MRT6_BASE 200 + * ... + * MRT6_MAX + */ +#endif /* _LINUX_IN6_H */ diff --git a/include/linux-private/linux/libc-compat.h b/include/linux-private/linux/libc-compat.h new file mode 100644 index 0000000..9bed5b6 --- /dev/null +++ b/include/linux-private/linux/libc-compat.h @@ -0,0 +1,143 @@ +/* + * Compatibility interface for userspace libc header coordination: + * + * Define compatibility macros that are used to control the inclusion or + * exclusion of UAPI structures and definitions in coordination with another + * userspace C library. + * + * This header is intended to solve the problem of UAPI definitions that + * conflict with userspace definitions. If a UAPI header has such conflicting + * definitions then the solution is as follows: + * + * * Synchronize the UAPI header and the libc headers so either one can be + * used and such that the ABI is preserved. If this is not possible then + * no simple compatibility interface exists (you need to write translating + * wrappers and rename things) and you can't use this interface. + * + * Then follow this process: + * + * (a) Include libc-compat.h in the UAPI header. + * e.g. #include <linux/libc-compat.h> + * This include must be as early as possible. + * + * (b) In libc-compat.h add enough code to detect that the comflicting + * userspace libc header has been included first. + * + * (c) If the userspace libc header has been included first define a set of + * guard macros of the form __UAPI_DEF_FOO and set their values to 1, else + * set their values to 0. + * + * (d) Back in the UAPI header with the conflicting definitions, guard the + * definitions with: + * #if __UAPI_DEF_FOO + * ... + * #endif + * + * This fixes the situation where the linux headers are included *after* the + * libc headers. To fix the problem with the inclusion in the other order the + * userspace libc headers must be fixed like this: + * + * * For all definitions that conflict with kernel definitions wrap those + * defines in the following: + * #if !__UAPI_DEF_FOO + * ... + * #endif + * + * This prevents the redefinition of a construct already defined by the kernel. + */ +#ifndef _LIBC_COMPAT_H +#define _LIBC_COMPAT_H + +/* We have included glibc headers... */ +#if defined(__GLIBC__) + +/* Coordinate with glibc netinet/in.h header. */ +#if defined(_NETINET_IN_H) + +/* GLIBC headers included first so don't define anything + * that would already be defined. */ +#define __UAPI_DEF_IN_ADDR 0 +#define __UAPI_DEF_IN_IPPROTO 0 +#define __UAPI_DEF_IN_PKTINFO 0 +#define __UAPI_DEF_IP_MREQ 0 +#define __UAPI_DEF_SOCKADDR_IN 0 +#define __UAPI_DEF_IN_CLASS 0 + +#define __UAPI_DEF_IN6_ADDR 0 +/* The exception is the in6_addr macros which must be defined + * if the glibc code didn't define them. This guard matches + * the guard in glibc/inet/netinet/in.h which defines the + * additional in6_addr macros e.g. s6_addr16, and s6_addr32. */ +#if defined(__USE_MISC) || defined (__USE_GNU) +#define __UAPI_DEF_IN6_ADDR_ALT 0 +#else +#define __UAPI_DEF_IN6_ADDR_ALT 1 +#endif +#define __UAPI_DEF_SOCKADDR_IN6 0 +#define __UAPI_DEF_IPV6_MREQ 0 +#define __UAPI_DEF_IPPROTO_V6 0 +#define __UAPI_DEF_IPV6_OPTIONS 0 +#define __UAPI_DEF_IN6_PKTINFO 0 +#define __UAPI_DEF_IP6_MTUINFO 0 + +#else + +/* 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_IN_ADDR 1 +#define __UAPI_DEF_IN_IPPROTO 1 +#define __UAPI_DEF_IN_PKTINFO 1 +#define __UAPI_DEF_IP_MREQ 1 +#define __UAPI_DEF_SOCKADDR_IN 1 +#define __UAPI_DEF_IN_CLASS 1 + +#define __UAPI_DEF_IN6_ADDR 1 +/* We unconditionally define the in6_addr macros and glibc must + * coordinate. */ +#define __UAPI_DEF_IN6_ADDR_ALT 1 +#define __UAPI_DEF_SOCKADDR_IN6 1 +#define __UAPI_DEF_IPV6_MREQ 1 +#define __UAPI_DEF_IPPROTO_V6 1 +#define __UAPI_DEF_IPV6_OPTIONS 1 +#define __UAPI_DEF_IN6_PKTINFO 1 +#define __UAPI_DEF_IP6_MTUINFO 1 + +#endif /* _NETINET_IN_H */ + +/* Definitions for xattr.h */ +#if defined(_SYS_XATTR_H) +#define __UAPI_DEF_XATTR 0 +#else +#define __UAPI_DEF_XATTR 1 +#endif + +/* If we did not see any headers from any supported C libraries, + * or we are being included in the kernel, then define everything + * that we need. */ +#else /* !defined(__GLIBC__) */ + +/* Definitions for in.h */ +#define __UAPI_DEF_IN_ADDR 1 +#define __UAPI_DEF_IN_IPPROTO 1 +#define __UAPI_DEF_IN_PKTINFO 1 +#define __UAPI_DEF_IP_MREQ 1 +#define __UAPI_DEF_SOCKADDR_IN 1 +#define __UAPI_DEF_IN_CLASS 1 + +/* Definitions for in6.h */ +#define __UAPI_DEF_IN6_ADDR 1 +#define __UAPI_DEF_IN6_ADDR_ALT 1 +#define __UAPI_DEF_SOCKADDR_IN6 1 +#define __UAPI_DEF_IPV6_MREQ 1 +#define __UAPI_DEF_IPPROTO_V6 1 +#define __UAPI_DEF_IPV6_OPTIONS 1 +#define __UAPI_DEF_IN6_PKTINFO 1 +#define __UAPI_DEF_IP6_MTUINFO 1 + +/* Definitions for xattr.h */ +#define __UAPI_DEF_XATTR 1 + +#endif /* __GLIBC__ */ + +#endif /* _LIBC_COMPAT_H */ diff --git a/include/linux-private/linux/rtnetlink.h b/include/linux-private/linux/rtnetlink.h index 2363c18..3244947 100644 --- a/include/linux-private/linux/rtnetlink.h +++ b/include/linux-private/linux/rtnetlink.h @@ -120,6 +120,25 @@ enum { RTM_SETDCB, #define RTM_SETDCB RTM_SETDCB + RTM_NEWNETCONF = 80, +#define RTM_NEWNETCONF RTM_NEWNETCONF + RTM_GETNETCONF = 82, +#define RTM_GETNETCONF RTM_GETNETCONF + + RTM_NEWMDB = 84, +#define RTM_NEWMDB RTM_NEWMDB + RTM_DELMDB = 85, +#define RTM_DELMDB RTM_DELMDB + RTM_GETMDB = 86, +#define RTM_GETMDB RTM_GETMDB + + RTM_NEWNSID = 88, +#define RTM_NEWNSID RTM_NEWNSID + RTM_DELNSID = 89, +#define RTM_DELNSID RTM_DELNSID + RTM_GETNSID = 90, +#define RTM_GETNSID RTM_GETNSID + __RTM_MAX, #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) }; @@ -141,7 +160,7 @@ struct rtattr { /* Macros to handle rtattributes */ -#define RTA_ALIGNTO 4 +#define RTA_ALIGNTO 4U #define RTA_ALIGN(len) ( ((len)+RTA_ALIGNTO-1) & ~(RTA_ALIGNTO-1) ) #define RTA_OK(rta,len) ((len) >= (int)sizeof(struct rtattr) && \ (rta)->rta_len >= sizeof(struct rtattr) && \ @@ -222,6 +241,8 @@ enum { #define RTPROT_XORP 14 /* XORP */ #define RTPROT_NTK 15 /* Netsukuku */ #define RTPROT_DHCP 16 /* DHCP client */ +#define RTPROT_MROUTED 17 /* Multicast daemon */ +#define RTPROT_BABEL 42 /* Babel daemon */ /* rtm_scope @@ -283,6 +304,12 @@ enum rtattr_type_t { RTA_MP_ALGO, /* no longer used */ RTA_TABLE, RTA_MARK, + RTA_MFC_STATS, + RTA_VIA, + RTA_NEWDST, + RTA_PREF, + RTA_ENCAP_TYPE, + RTA_ENCAP, __RTA_MAX }; @@ -312,6 +339,10 @@ struct rtnexthop { #define RTNH_F_DEAD 1 /* Nexthop is dead (used by multipath) */ #define RTNH_F_PERVASIVE 2 /* Do recursive gateway lookup */ #define RTNH_F_ONLINK 4 /* Gateway is forced on link */ +#define RTNH_F_OFFLOAD 8 /* offloaded route */ +#define RTNH_F_LINKDOWN 16 /* carrier-down on nexthop */ + +#define RTNH_COMPARE_MASK (RTNH_F_DEAD | RTNH_F_LINKDOWN) /* Macros to handle hexthops */ @@ -324,6 +355,12 @@ struct rtnexthop { #define RTNH_SPACE(len) RTNH_ALIGN(RTNH_LENGTH(len)) #define RTNH_DATA(rtnh) ((struct rtattr*)(((char*)(rtnh)) + RTNH_LENGTH(0))) +/* RTA_VIA */ +struct rtvia { + __kernel_sa_family_t rtvia_family; + __u8 rtvia_addr[0]; +}; + /* RTM_CACHEINFO */ struct rta_cacheinfo { @@ -372,15 +409,22 @@ enum { #define RTAX_RTO_MIN RTAX_RTO_MIN RTAX_INITRWND, #define RTAX_INITRWND RTAX_INITRWND + RTAX_QUICKACK, +#define RTAX_QUICKACK RTAX_QUICKACK + RTAX_CC_ALGO, +#define RTAX_CC_ALGO RTAX_CC_ALGO __RTAX_MAX }; #define RTAX_MAX (__RTAX_MAX - 1) -#define RTAX_FEATURE_ECN 0x00000001 -#define RTAX_FEATURE_SACK 0x00000002 -#define RTAX_FEATURE_TIMESTAMP 0x00000004 -#define RTAX_FEATURE_ALLFRAG 0x00000008 +#define RTAX_FEATURE_ECN (1 << 0) +#define RTAX_FEATURE_SACK (1 << 1) +#define RTAX_FEATURE_TIMESTAMP (1 << 2) +#define RTAX_FEATURE_ALLFRAG (1 << 3) + +#define RTAX_FEATURE_MASK (RTAX_FEATURE_ECN | RTAX_FEATURE_SACK | \ + RTAX_FEATURE_TIMESTAMP | RTAX_FEATURE_ALLFRAG) struct rta_session { __u8 proto; @@ -403,6 +447,12 @@ struct rta_session { } u; }; +struct rta_mfc_stats { + __u64 mfcs_packets; + __u64 mfcs_bytes; + __u64 mfcs_wrong_if; +}; + /**** * General form of address family dependent message. ****/ @@ -516,7 +566,6 @@ enum { #define NDUSEROPT_MAX (__NDUSEROPT_MAX - 1) -#ifndef __KERNEL__ /* RTnetlink multicast groups - backwards compatibility for userspace */ #define RTMGRP_LINK 1 #define RTMGRP_NOTIFY 2 @@ -537,7 +586,6 @@ enum { #define RTMGRP_DECnet_ROUTE 0x4000 #define RTMGRP_IPV6_PREFIX 0x20000 -#endif /* RTnetlink multicast groups */ enum rtnetlink_groups { @@ -585,6 +633,18 @@ enum rtnetlink_groups { #define RTNLGRP_PHONET_IFADDR RTNLGRP_PHONET_IFADDR RTNLGRP_PHONET_ROUTE, #define RTNLGRP_PHONET_ROUTE RTNLGRP_PHONET_ROUTE + RTNLGRP_DCB, +#define RTNLGRP_DCB RTNLGRP_DCB + RTNLGRP_IPV4_NETCONF, +#define RTNLGRP_IPV4_NETCONF RTNLGRP_IPV4_NETCONF + RTNLGRP_IPV6_NETCONF, +#define RTNLGRP_IPV6_NETCONF RTNLGRP_IPV6_NETCONF + RTNLGRP_MDB, +#define RTNLGRP_MDB RTNLGRP_MDB + RTNLGRP_MPLS_ROUTE, +#define RTNLGRP_MPLS_ROUTE RTNLGRP_MPLS_ROUTE + RTNLGRP_NSID, +#define RTNLGRP_NSID RTNLGRP_NSID __RTNLGRP_MAX }; #define RTNLGRP_MAX (__RTNLGRP_MAX - 1) @@ -600,6 +660,13 @@ struct tcamsg { #define TCA_ACT_TAB 1 /* attr type must be >=1 */ #define TCAA_MAX 1 +/* New extended info filters for IFLA_EXT_MASK */ +#define RTEXT_FILTER_VF (1 << 0) +#define RTEXT_FILTER_BRVLAN (1 << 1) +#define RTEXT_FILTER_BRVLAN_COMPRESSED (1 << 2) + /* End of information exported to user level */ -#endif /* __LINUX_RTNETLINK_H */ + + +#endif /* __LINUX_RTNETLINK_H */ diff --git a/include/netlink-private/route/link/api.h b/include/netlink-private/route/link/api.h index 85f83f3..6e11062 100644 --- a/include/netlink-private/route/link/api.h +++ b/include/netlink-private/route/link/api.h @@ -119,6 +119,15 @@ struct rtnl_link_af_ops int (*ao_fill_af)(struct rtnl_link *, struct nl_msg *msg, void *); + /** Called if the full IFLA_AF_SPEC data needs to be parsed. Typically + * stores the parsed data in the address family specific buffer. */ + int (*ao_parse_af_full)(struct rtnl_link *, + struct nlattr *, void *); + + /** Called for GETLINK message to the kernel. Used to append + * link address family specific attributes to the request message. */ + int (*ao_get_af)(struct nl_msg *msg); + /** Dump address family specific link attributes */ void (*ao_dump[NL_DUMP_MAX+1])(struct rtnl_link *, struct nl_dump_params *, diff --git a/include/netlink/route/link/bridge.h b/include/netlink/route/link/bridge.h index 16a4505..a314d77 100644 --- a/include/netlink/route/link/bridge.h +++ b/include/netlink/route/link/bridge.h @@ -19,6 +19,16 @@ extern "C" { #endif +#define RTNL_LINK_BRIDGE_VLAN_BITMAP_MAX 4096 +#define RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN (RTNL_LINK_BRIDGE_VLAN_BITMAP_MAX / 32) + +struct rtnl_link_bridge_vlan +{ + uint16_t pvid; + uint32_t vlan_bitmap[RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN]; + uint32_t untagged_bitmap[RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN]; +}; + /** * Bridge flags * @ingroup bridge @@ -52,6 +62,11 @@ extern char * rtnl_link_bridge_flags2str(int, char *, size_t); extern int rtnl_link_bridge_str2flags(const char *); extern int rtnl_link_bridge_add(struct nl_sock *sk, const char *name); + +extern int rtnl_link_bridge_pvid(struct rtnl_link *link); +extern int rtnl_link_bridge_has_vlan(struct rtnl_link *link); + +extern struct bridge_vlan *rtnl_bridge_get_port_vlan(struct rtnl_link *link); #ifdef __cplusplus } #endif diff --git a/lib/route/link.c b/lib/route/link.c index cfe3779..d763d97 100644 --- a/lib/route/link.c +++ b/lib/route/link.c @@ -496,6 +496,7 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, struct ifinfomsg *ifi; struct nlattr *tb[IFLA_MAX+1]; struct rtnl_link_af_ops *af_ops = NULL; + struct rtnl_link_af_ops *af_ops_family; int err, family; struct nla_policy real_link_policy[IFLA_MAX+1]; @@ -524,7 +525,7 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX | LINK_ATTR_FLAGS | LINK_ATTR_CHANGE); - if ((af_ops = af_lookup_and_alloc(link, family))) { + if ((af_ops_family = af_ops = af_lookup_and_alloc(link, family))) { if (af_ops->ao_protinfo_policy) { memcpy(&real_link_policy[IFLA_PROTINFO], af_ops->ao_protinfo_policy, @@ -570,7 +571,7 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, if (af_ops->ao_protinfo_policy) { tb[IFLA_PROTINFO] = (struct nlattr *)af_ops->ao_protinfo_policy; } - link->l_family = family = af; + link->l_family = af; link->l_af_ops = af_ops; } @@ -601,21 +602,35 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, } if (tb[IFLA_AF_SPEC]) { - struct nlattr *af_attr; - int remaining; + /* parsing of IFLA_AF_SPEC is dependent on the family used + * in the request message. + */ + if (af_ops_family && af_ops_family->ao_parse_af_full) { + err = af_ops_family->ao_parse_af_full(link, + tb[IFLA_AF_SPEC], + link->l_af_data[af_ops_family->ao_family]); + if (err < 0) + goto errout; + link->ce_mask |= LINK_ATTR_AF_SPEC; + } else if (family == AF_UNSPEC) { + struct nlattr *af_attr; + int remaining; - nla_for_each_nested(af_attr, tb[IFLA_AF_SPEC], remaining) { - af_ops = af_lookup_and_alloc(link, nla_type(af_attr)); - if (af_ops && af_ops->ao_parse_af) { - char *af_data = link->l_af_data[nla_type(af_attr)]; + nla_for_each_nested(af_attr, tb[IFLA_AF_SPEC], remaining) { + af_ops = af_lookup_and_alloc(link, nla_type(af_attr)); + if (af_ops && af_ops->ao_parse_af) { + char *af_data = link->l_af_data[nla_type(af_attr)]; - err = af_ops->ao_parse_af(link, af_attr, af_data); - if (err < 0) - goto errout; + err = af_ops->ao_parse_af(link, af_attr, af_data); + if (err < 0) + goto errout; + } } - + link->ce_mask |= LINK_ATTR_AF_SPEC; + } else { + NL_DBG(3, "IFLA_AF_SPEC parsing not implemented for family %d\n", + family); } - link->ce_mask |= LINK_ATTR_AF_SPEC; } if (tb[IFLA_PROMISCUITY]) { @@ -657,8 +672,32 @@ errout: static int link_request_update(struct nl_cache *cache, struct nl_sock *sk) { int family = cache->c_iarg1; + struct ifinfomsg hdr = { .ifi_family = family }; + struct rtnl_link_af_ops *ops; + struct nl_msg *msg; + int err; - return nl_rtgen_request(sk, RTM_GETLINK, family, NLM_F_DUMP); + msg = nlmsg_alloc_simple(RTM_GETLINK, NLM_F_DUMP); + if (!msg) + return -NLE_NOMEM; + + err = -NLE_MSGSIZE; + if (nlmsg_append(msg, &hdr, sizeof(hdr), NLMSG_ALIGNTO) < 0) + goto nla_put_failure; + + ops = rtnl_link_af_ops_lookup(family); + if (ops && ops->ao_get_af) { + err = ops->ao_get_af(msg); + if (err) + goto nla_put_failure; + } + err = nl_send_auto(sk, msg); + if (err > 0) + err = 0; + +nla_put_failure: + nlmsg_free(msg); + return err; } static void link_dump_line(struct nl_object *obj, struct nl_dump_params *p) diff --git a/lib/route/link/bridge.c b/lib/route/link/bridge.c index 544f02c..75d5792 100644 --- a/lib/route/link/bridge.c +++ b/lib/route/link/bridge.c @@ -25,11 +25,14 @@ #include <netlink-private/route/link/api.h> #include <linux/if_bridge.h> +#define VLAN_VID_MASK 0x0fff /* VLAN Identifier */ + /** @cond SKIP */ #define BRIDGE_ATTR_PORT_STATE (1 << 0) #define BRIDGE_ATTR_PRIORITY (1 << 1) #define BRIDGE_ATTR_COST (1 << 2) #define BRIDGE_ATTR_FLAGS (1 << 3) +#define BRIDGE_ATTR_PORT_VLAN (1 << 4) #define PRIV_FLAG_NEW_ATTRS (1 << 0) @@ -42,8 +45,31 @@ struct bridge_data uint32_t b_flags; uint32_t b_flags_mask; uint32_t ce_mask; /* HACK to support attr macros */ + struct rtnl_link_bridge_vlan vlan_info; }; +static void set_bit(unsigned nr, uint32_t *addr) +{ + if (nr < RTNL_LINK_BRIDGE_VLAN_BITMAP_MAX) + addr[nr / 32] |= (((uint32_t) 1) << (nr % 32)); +} + +static int find_next_bit(int i, uint32_t x) +{ + int j; + + if (i >= 32) + return -1; + + /* find first bit */ + if (i < 0) + return __builtin_ffs(x); + + /* mask off prior finds to get next */ + j = __builtin_ffs(x >> i); + return j ? j + i : 0; +} + static struct rtnl_link_af_ops bridge_ops; #define IS_BRIDGE_LINK_ASSERT(link) \ @@ -141,6 +167,135 @@ static int bridge_parse_protinfo(struct rtnl_link *link, struct nlattr *attr, return 0; } +static int bridge_parse_af_full(struct rtnl_link *link, struct nlattr *attr_full, + void *data) +{ + struct bridge_data *bd = data; + struct bridge_vlan_info *vinfo = NULL; + uint16_t vid_range_start = 0; + uint16_t vid_range_flags = -1; + + struct nlattr *attr; + int remaining; + + nla_for_each_nested(attr, attr_full, remaining) { + + if (nla_type(attr) != IFLA_BRIDGE_VLAN_INFO) + continue; + + if (nla_len(attr) != sizeof(struct bridge_vlan_info)) + return -EINVAL; + + vinfo = nla_data(attr); + if (!vinfo->vid || vinfo->vid >= VLAN_VID_MASK) + return -EINVAL; + + + if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) { + vid_range_start = vinfo->vid; + vid_range_flags = (vinfo->flags ^ BRIDGE_VLAN_INFO_RANGE_BEGIN); + continue; + } + + if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END) { + /* sanity check the range flags */ + if (vid_range_flags != (vinfo->flags ^ BRIDGE_VLAN_INFO_RANGE_END)) { + NL_DBG(1, "VLAN range flags differ; can not handle it.\n"); + return -EINVAL; + } + } else { + vid_range_start = vinfo->vid; + } + + for (; vid_range_start <= vinfo->vid; vid_range_start++) { + if (vinfo->flags & BRIDGE_VLAN_INFO_PVID) + bd->vlan_info.pvid = vinfo->vid; + + if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED) + set_bit(vid_range_start, bd->vlan_info.untagged_bitmap); + + set_bit(vid_range_start, bd->vlan_info.vlan_bitmap); + bd->ce_mask |= BRIDGE_ATTR_PORT_VLAN; + } + + vid_range_flags = -1; + } + + return 0; +} + +static int bridge_get_af(struct nl_msg *msg) +{ + __u32 ext_filter_mask = RTEXT_FILTER_BRVLAN; + + return nla_put(msg, IFLA_EXT_MASK, sizeof(ext_filter_mask), &ext_filter_mask); +} + +static void dump_bitmap(struct nl_dump_params *p, const uint32_t *b) +{ + int i = -1, j, k; + int start = -1, prev = -1; + int done, found = 0; + + for (k = 0; k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; k++) { + int base_bit; + uint32_t a = b[k]; + + base_bit = k * 32; + i = -1; + done = 0; + while (!done) { + j = find_next_bit(i, a); + if (j > 0) { + /* first hit of any bit */ + if (start < 0 && prev < 0) { + start = prev = j - 1 + base_bit; + goto next; + } + /* this bit is a continuation of prior bits */ + if (j - 2 + base_bit == prev) { + prev++; + goto next; + } + } else + done = 1; + + if (start >= 0) { + found++; + if (done && k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN - 1) + break; + + nl_dump(p, " %d", start); + if (start != prev) + nl_dump(p, "-%d", prev); + + if (done) + break; + } + if (j > 0) + start = prev = j - 1 + base_bit; +next: + i = j; + } + } + if (!found) + nl_dump(p, " <none>"); + + return; +} + +static void rtnl_link_bridge_dump_vlans(struct nl_dump_params *p, + struct bridge_data *bd) +{ + nl_dump(p, "pvid %u", bd->vlan_info.pvid); + + nl_dump(p, " all vlans:"); + dump_bitmap(p, bd->vlan_info.vlan_bitmap); + + nl_dump(p, " untagged vlans:"); + dump_bitmap(p, bd->vlan_info.untagged_bitmap); +} + static void bridge_dump_details(struct rtnl_link *link, struct nl_dump_params *p, void *data) { @@ -157,6 +312,17 @@ static void bridge_dump_details(struct rtnl_link *link, if (bd->ce_mask & BRIDGE_ATTR_COST) nl_dump(p, "cost %u ", bd->b_cost); + if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN) + rtnl_link_bridge_dump_vlans(p, bd); + + if (bd->ce_mask & BRIDGE_ATTR_FLAGS) { + char buf[256]; + + rtnl_link_bridge_flags2str(bd->b_flags & bd->b_flags_mask, + buf, sizeof(buf)); + nl_dump(p, "%s", buf); + } + nl_dump(p, "\n"); } @@ -171,6 +337,8 @@ static int bridge_compare(struct rtnl_link *_a, struct rtnl_link *_b, diff |= BRIDGE_DIFF(PORT_STATE, a->b_port_state != b->b_port_state); diff |= BRIDGE_DIFF(PRIORITY, a->b_priority != b->b_priority); diff |= BRIDGE_DIFF(COST, a->b_cost != b->b_cost); + diff |= BRIDGE_DIFF(PORT_VLAN, memcmp(&a->vlan_info, &b->vlan_info, + sizeof(struct rtnl_link_bridge_vlan))); if (flags & LOOSE_COMPARISON) diff |= BRIDGE_DIFF(FLAGS, @@ -503,6 +671,54 @@ int rtnl_link_bridge_str2flags(const char *name) /** @} */ +int rtnl_link_bridge_pvid(struct rtnl_link *link) +{ + struct bridge_data *bd; + + IS_BRIDGE_LINK_ASSERT(link); + + bd = link->l_af_data[AF_BRIDGE]; + if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN) + return (int) bd->vlan_info.pvid; + + return -EINVAL; +} + +int rtnl_link_bridge_has_vlan(struct rtnl_link *link) +{ + struct bridge_data *bd; + int i; + + IS_BRIDGE_LINK_ASSERT(link); + + bd = link->l_af_data[AF_BRIDGE]; + if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN) { + if (bd->vlan_info.pvid) + return 1; + + for (i = 0; i < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; ++i) { + if (bd->vlan_info.vlan_bitmap[i] || + bd->vlan_info.untagged_bitmap[i]) + return 1; + } + } + return 0; +} + +struct rtnl_link_bridge_vlan *rtnl_link_bridge_get_port_vlan(struct rtnl_link *link) +{ + struct bridge_data *data; + + if (!rtnl_link_is_bridge(link)) + return NULL; + + data = link->l_af_data[AF_BRIDGE]; + if (data && (data->ce_mask & BRIDGE_ATTR_PORT_VLAN)) + return &data->vlan_info; + + return NULL; +} + static struct rtnl_link_af_ops bridge_ops = { .ao_family = AF_BRIDGE, .ao_alloc = &bridge_alloc, @@ -511,6 +727,8 @@ static struct rtnl_link_af_ops bridge_ops = { .ao_parse_protinfo = &bridge_parse_protinfo, .ao_dump[NL_DUMP_DETAILS] = &bridge_dump_details, .ao_compare = &bridge_compare, + .ao_parse_af_full = &bridge_parse_af_full, + .ao_get_af = &bridge_get_af, }; static void __init bridge_init(void) diff --git a/lib/route/neigh.c b/lib/route/neigh.c index 6059e7f..436d766 100644 --- a/lib/route/neigh.c +++ b/lib/route/neigh.c @@ -210,6 +210,7 @@ static void neigh_keygen(struct nl_object *obj, uint32_t *hashkey, struct neigh_hash_key { uint32_t n_family; uint32_t n_ifindex; + uint16_t n_vlan; char n_addr[0]; } __attribute__((packed)) *nkey; #ifdef NL_DEBUG @@ -234,6 +235,7 @@ static void neigh_keygen(struct nl_object *obj, uint32_t *hashkey, } nkey->n_family = neigh->n_family; if (neigh->n_family == AF_BRIDGE) { + nkey->n_vlan = neigh->n_vlan; if (neigh->n_flags & NTF_SELF) nkey->n_ifindex = neigh->n_ifindex; else @@ -316,9 +318,9 @@ static uint32_t neigh_id_attrs_get(struct nl_object *obj) if (neigh->n_family == AF_BRIDGE) { if (neigh->n_flags & NTF_SELF) - return (NEIGH_ATTR_LLADDR | NEIGH_ATTR_FAMILY | NEIGH_ATTR_IFINDEX); + return (NEIGH_ATTR_LLADDR | NEIGH_ATTR_FAMILY | NEIGH_ATTR_IFINDEX | NEIGH_ATTR_VLAN); else - return (NEIGH_ATTR_LLADDR | NEIGH_ATTR_FAMILY | NEIGH_ATTR_MASTER); + return (NEIGH_ATTR_LLADDR | NEIGH_ATTR_FAMILY | NEIGH_ATTR_MASTER | NEIGH_ATTR_VLAN); } else return (NEIGH_ATTR_IFINDEX | NEIGH_ATTR_DST | NEIGH_ATTR_FAMILY); } @@ -472,6 +474,9 @@ static void neigh_dump_line(struct nl_object *a, struct nl_dump_params *p) nl_dump(p, "lladdr %s ", nl_addr2str(n->n_lladdr, lladdr, sizeof(lladdr))); + if (n->ce_mask & NEIGH_ATTR_VLAN) + nl_dump(p, "vlan %d ", n->n_vlan); + rtnl_neigh_state2str(n->n_state, state, sizeof(state)); rtnl_neigh_flags2str(n->n_flags, flags, sizeof(flags)); diff --git a/libnl-route-3.sym b/libnl-route-3.sym index 627cb43..2400746 100644 --- a/libnl-route-3.sym +++ b/libnl-route-3.sym @@ -904,5 +904,8 @@ global: rtnl_link_vrf_get_tableid; rtnl_link_vrf_set_tableid; rtnl_neigh_alloc_cache_flags; + rtnl_link_bridge_pvid; + rtnl_link_bridge_has_vlan; + rtnl_link_bridge_get_port_vlan; } libnl_3_2_27; |