batctl: introduce rtnl_open() helper function
PATCH 1/3 batctl: introduce rtnl_open() helper function
Other part of batctl may require to open and send a message to RTNL. Extract this code and put it in a generic helper to simplify future uses.
--- functions.c | 46 ++++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 16 deletions(-)
functions.c +30 -16
@@ -497,30 +497,28 @@ static void request_mac_resolve(int ai_family, const void *l3addr)close (sock); } -static int resolve_mac_from_cache_open (int ai_family) +/** +* rtnl_open - open a socket to rtnl and send a request +* @req: the buffer containing the request to send +* @len: the length of the buffer containing the request +* @protocol: the protocol to use when opening the socket +* +* Return 0 on success or a negative error code otherwise +*/ +static int rtnl_open (void *req,size_t len,int protocol) { -int socknl; -int ret; -struct { -struct nlmsghdr hdr; -struct ndmsg msg; - } nlreq; -struct sockaddr_nl addrnl;static uint32_t nr_call =0 ;uint32_t pid = (++nr_call +getpid ()) &0x3FFFFF ; +struct sockaddr_nl addrnl; +int socknl; +int ret;memset (&addrnl,0 ,sizeof (addrnl)); addrnl.nl_family =AF_NETLINK ; addrnl.nl_pid = pid; addrnl.nl_groups =0 ; -memset (&nlreq,0 ,sizeof (nlreq)); - nlreq.hdr.nlmsg_len =NLMSG_LENGTH (sizeof (nlreq.msg)); - nlreq.hdr.nlmsg_type =RTM_GETNEIGH ; - nlreq.hdr.nlmsg_flags =NLM_F_REQUEST |NLM_F_DUMP ; - nlreq.msg.ndm_family = ai_family; - - socknl =socket (AF_NETLINK ,SOCK_RAW ,NETLINK_ROUTE ); + socknl =socket (AF_NETLINK ,SOCK_RAW , protocol);if (socknl <0 ) goto out;
@@ -528,7 +526,7 @@ static int resolve_mac_from_cache_open(int ai_family)if (ret <0 ) goto outclose; - ret =send (socknl, &nlreq, nlreq.hdr.nlmsg_len,0 ); + ret =send (socknl, req, len,0 );if (ret <0 ) goto outclose; out:
@@ -538,6 +536,22 @@ outclose:return ret; } +static int resolve_mac_from_cache_open (int ai_family) +{ +struct { +struct nlmsghdr hdr; +struct ndmsg msg; + } nlreq; + +memset (&nlreq,0 ,sizeof (nlreq)); + nlreq.hdr.nlmsg_len =NLMSG_LENGTH (sizeof (nlreq.msg)); + nlreq.hdr.nlmsg_type =RTM_GETNEIGH ; + nlreq.hdr.nlmsg_flags =NLM_F_REQUEST |NLM_F_DUMP ; + nlreq.msg.ndm_family = ai_family; + +return rtnl_open (&nlreq,sizeof (nlreq),NETLINK_ROUTE ); +} +static ssize_t resolve_mac_from_cache_dump (int sock,void **buf,size_t *buflen) {struct iovec iov;
Signature · 1 line
1.8.5.2
PATCH 2/3 batctl: implement vlan-to-link helper functions
This functions can be used to convert a vlan interface into the real one and to extract the vlan identifier.
--- functions.c | 180 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ functions.h | 1 + 2 files changed, 181 insertions(+)
functions.c +180 -0
@@ -40,6 +40,7 @@#include <linux/neighbour.h> #include <sys/uio.h> #include <errno.h> +#include <net/if.h> #include "main.h" #include "functions.h"
@@ -765,3 +766,182 @@ struct ether_addr *resolve_mac(const char *asc) out:return mac_result; } + +/** +* vlan_get_link_parse - parse a get_link rtnl message and extract the important +* data +* @nh: the reply header +* @iface: pointer to the buffer where the link interface has to be stored (it +* is allocated by this function) +* +* Return the vid in case of success or -1 otherwise +*/ +static int vlan_get_link_parse (struct nlmsghdr *nh,char **iface) +{ +struct ifinfomsg *ifi =NLMSG_DATA (nh); +size_t vlan_len, info_len, len = nh->nlmsg_len; +struct rtattr *rta, *info, *vlan; +int idx =-1 , vid =-1 ; + + *iface =NULL ; + + rta =IFLA_RTA (ifi); +while (RTA_OK (rta, len)) { +/* check if the interface is a vlan */ +if (rta->rta_type ==IFLA_LINKINFO ) { + info =RTA_DATA (rta); + info_len =RTA_PAYLOAD (rta); + +while (RTA_OK (info, info_len)) { +if (info->rta_type ==IFLA_INFO_KIND && +strcmp (RTA_DATA (info),"vlan" )) { +fprintf (stderr, +"Interface is not a VLAN\n" ); + goto err; + } + +if (info->rta_type ==IFLA_INFO_DATA ) { + vlan =RTA_DATA (info); + vlan_len =RTA_PAYLOAD (info); + +while (RTA_OK (vlan, vlan_len)) { +if (vlan->rta_type ==IFLA_VLAN_ID ) + vid = *(int *)RTA_DATA (vlan); + vlan =RTA_NEXT (vlan, vlan_len); + } + } + info =RTA_NEXT (info, info_len); + } + } + +/* extract the name of the "link" interface */ +if (rta->rta_type ==IFLA_LINK ) { + idx = *(int *)RTA_DATA (rta); + + *iface =malloc (IFNAMSIZ +1 ); +if (!if_indextoname (idx, *iface)) + goto err; + } + rta =RTA_NEXT (rta, len); + } + +if (vid ==-1 ) { +fprintf (stderr,"Couldn't find a valid VLAN ID for this interface\n" ); + goto err; + } + +if (idx <=0 ) { +fprintf (stderr,"Couldn't find a valid parent interface\n" ); + goto err; + } + +return vid; +err: +free (*iface); +return -1 ; +} + +/** +* vlan_get_link_dump - receive and dump a get_link rtnl reply +* @sock: the socket to listen for the reply on +* @buf: pointer to the buffer where the reply has to be dumped to +* @buflen: length of the buffer +* +* Returns the amount of dumped bytes +*/ +static ssize_t vlan_get_link_dump (int sock,void *buf,size_t buflen) +{ +struct iovec iov; +struct msghdr msg; +struct sockaddr_nl nladdr; +ssize_t ret =-1 ; + +memset (&msg,0 ,sizeof (msg)); +memset (&iov,0 ,sizeof (iov)); + + msg.msg_iov = &iov; + msg.msg_iovlen =1 ; + msg.msg_controllen =0 ; + msg.msg_control =NULL ; + msg.msg_flags =0 ; + msg.msg_name = &nladdr; + msg.msg_namelen =sizeof (nladdr); + + iov.iov_len = buflen; + iov.iov_base = buf; + + ret =recvmsg (sock, &msg,0 ); +if (ret <0 ) + goto err; + +return ret; +err: +free (buf); +return ret; +} + +/** +* vlan_get_link_open - send a get_link request +* @ifname: the interface to query +* +* Returns 0 in case of success or a negative error code otherwise +*/ +static int vlan_get_link_open (const char *ifname) +{ +struct { +struct nlmsghdr hdr; +struct ifinfomsg ifi; +/* attribute has to be NLMAG aligned */ +struct rtattr rta_ifname __attribute__ ((aligned (NLMSG_ALIGNTO ))); +char ifname[IFNAMSIZ +1 ]; + } nlreq; + +memset (&nlreq,0 ,sizeof (nlreq)); + nlreq.hdr.nlmsg_len =sizeof (nlreq); + nlreq.hdr.nlmsg_type =RTM_GETLINK ; + nlreq.hdr.nlmsg_flags =NLM_F_REQUEST ; + nlreq.ifi.ifi_family =AF_UNSPEC ; + + nlreq.rta_ifname.rta_type =IFLA_IFNAME ; + nlreq.rta_ifname.rta_len =IFNAMSIZ +1 ; +strncpy (nlreq.ifname, ifname,IFNAMSIZ ); + +return rtnl_open (&nlreq,sizeof (nlreq),0 ); +} + +/** +* vlan_get_link - convert a VLAN interface into its parent one +* @ifname: the interface to convert +* @parent: buffer where the parent interface name will be written (allocated by +* this function) +* +* Returns the vlan identifier on success or -1 on error +*/ +int vlan_get_link (const char *ifname,char **parent) +{ +int vid =-1 , socknl; +void *buf =NULL ; +size_t buflen; +ssize_t len; + + buflen =8192 ; + buf =malloc (buflen); +if (!buf) + goto err; + + socknl =vlan_get_link_open (ifname); +if (socknl <0 ) + goto err; + + len =vlan_get_link_dump (socknl, buf, buflen); +if (len <0 ) + goto err_sock; + + vid =vlan_get_link_parse (buf, parent); + +err_sock: +close (socknl); +err: +free (buf); +return vid; +}
functions.h +1 -0
@@ -42,6 +42,7 @@ int write_file(const char *dir, const char *fname, const char *arg1, const char *arg2);struct ether_addr *translate_mac (char *mesh_iface,struct ether_addr *mac);struct ether_addr *resolve_mac (const char *asc); +int vlan_get_link (const char *ifname,char **parent);extern char *line_ptr;
Signature · 1 line
1.8.5.2
Re: [B.A.T.M.A.N.] [PATCH next 2/3] batctl: implement vlan-to-link helper functions
Quoted 28 lines · On Sunday 05 January 2014 09:59:53 Antonio Quartulli wrote:
functions.c +28
-0+/** +* vlan_get_link_dump - receive and dump a get_link rtnl reply +* @sock: the socket to listen for the reply on +* @buf: pointer to the buffer where the reply has to be dumped to +* @buflen: length of the buffer +* +* Returns the amount of dumped bytes +*/ +static ssize_t vlan_get_link_dump (int sock,void *buf,size_t buflen) +{ +struct iovec iov; +struct msghdr msg; +struct sockaddr_nl nladdr; +ssize_t ret =-1 ; + +memset (&msg,0 ,sizeof (msg)); +memset (&iov,0 ,sizeof (iov)); + + msg.msg_iov = &iov; + msg.msg_iovlen =1 ; + msg.msg_controllen =0 ; + msg.msg_control =NULL ; + msg.msg_flags =0 ; + msg.msg_name = &nladdr; + msg.msg_namelen =sizeof (nladdr); + + iov.iov_len = buflen; + iov.iov_base = buf;
functions.c struct ether_addr *resolve_mac(const char *asc) · line 881
Quoted 10 lines
functions.c +10
-0+ + ret =recvmsg (sock, &msg,0 ); +if (ret <0 ) + goto err; + +return ret; +err: +free (buf); +return ret; +}
Do we double free 'buf' in case of an error ?
functions.c struct ether_addr *resolve_mac(const char *asc) · line 894
Quoted 12 lines
functions.c +12
-0+/** +* vlan_get_link_open - send a get_link request +* @ifname: the interface to query +* +* Returns 0 in case of success or a negative error code otherwise +*/ +static int vlan_get_link_open (const char *ifname) +{ +struct { +struct nlmsghdr hdr; +struct ifinfomsg ifi; +/* attribute has to be NLMAG aligned */
NLMSG aligned ?
Cheers,
Marek
Re: [B.A.T.M.A.N.] [PATCH next 2/3] batctl: implement vlan-to-link helper functions
Quoted 9 lines · Marek Lindner
functions.c struct ether_addr *resolve_mac(const char *asc) · line 894
Quoted 6 lines · On Sunday 05 January 2014 09:59:53 Antonio Quartulli wrote:
functions.c +6
-0+static int vlan_get_link_open (const char *ifname) +{ +struct { +struct nlmsghdr hdr; +struct ifinfomsg ifi; +/* attribute has to be NLMAG aligned */ NLMSG aligned ?
Yes, you are right!
Thanks,
Signature · 1 line
Antonio Quartulli
PATCH 3/3 batctl: add sys framework for VLAN support
In reply to Antonio QuartulliFrom: Marco Dalla Torre <[email protected]>
Allow the batctl tool to take advantage of changes from commit e4ff5c153dab054a6cd1c4132f87bc5e77127456 "add sys framework for VLAN" recently added to batman-adv, so that users can execute commands in a per VLAN fashion.
If no directory entry corresponding to the user-selected device is found at the standard location for non VLAN interfaces (/sys/class/net/${device}/mesh/), 'batctl' now looks into directory:
/sys/class/net/${base_device}/mesh/vlan${vid}
Information on VLAN devices (base device, vid) necessary to construct the
directory path is acquired by querying the netlink kernel module.
Where:
-${base_device}: the batman device on top of which the VLAN is sitting
-${device}: the device interface for the VLAN,
-${vid}: the identifier assigned to the VLAN.If the user-selected command is not supported by the VLAN, an appropriate error is shown.
--- functions.c | 3 +++ main.c | 2 +- man/batctl.8 | 4 ++-- sys.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- sys.h | 22 ++++++++++++---------- 5 files changed, 66 insertions(+), 14 deletions(-)
functions.c +3 -0
@@ -143,6 +143,9 @@ static void file_open_problem_dbg(const char *dir, const char *fname,fprintf (stderr,"Error - the folder '/sys/' was not found on the system\n" );fprintf (stderr,"Please make sure that the sys filesystem is properly mounted\n" );return ; + }else if (strstr (dir,"/sys/devices/virtual/" )) { +fprintf (stderr,"The selected feature '%s' is not supported for vlans\n" , fname); +return ; } }
main.c +1 -1
@@ -46,7 +46,7 @@ static void print_usage(void)fprintf (stderr,"Usage: batctl [options] command|debug table [parameters]\n" );fprintf (stderr,"options:\n" ); -fprintf (stderr," \t-m mesh interface (default 'bat0')\n" ); +fprintf (stderr," \t-m mesh interface or mesh-based VLAN interface (default 'bat0')\n" );fprintf (stderr," \t-h print this help (or 'batctl <command|debug table> -h' for the parameter help)\n" );fprintf (stderr," \t-v print version\n" );fprintf (stderr,"\n" );
man/batctl.8 +2 -2
@@ -42,7 +42,7 @@ behaviour or using the B.A.T.M.A.N. advanced protocol. .SH OPTIONS .TP .I \fBoptions: -\-m specify mesh interface (default 'bat0') +\-m specify mesh interface or a mesh-based VLAN interface (default 'bat0') .br \-h print general batctl help .br
@@ -61,7 +61,7 @@ originator interval. The interval is in units of milliseconds. .br .IP "\fBap_isolation\fP|\fBap\fP [\fB0\fP|\fB1\fP]" If no parameter is given the current ap isolation setting is displayed. Otherwise the parameter is used to enable or -disable ap isolation. +disable ap isolation. This command can be used in conjunction with "-m" option to target per VLAN configurations. .br .IP "\fBbridge_loop_avoidance\fP|\fBbl\fP [\fB0\fP|\fB1\fP]" If no parameter is given the current bridge loop avoidance setting is displayed. Otherwise the parameter is used to enable
sys.c +48 -1
63 lines not on this page · raw message
sys.h +12 -10
@@ -24,16 +24,18 @@#include "main.h" -#define SYS_BATIF_PATH_FMT "/sys/class/net/%s/mesh/" -#define SYS_LOG_LEVEL "log_level" -#define SYS_LOG "log" -#define SYS_GW_MODE "gw_mode" -#define SYS_GW_SEL "gw_sel_class" -#define SYS_GW_BW "gw_bandwidth" -#define SYS_IFACE_PATH "/sys/class/net" -#define SYS_IFACE_DIR SYS_IFACE_PATH"/%s/" -#define SYS_MESH_IFACE_FMT SYS_IFACE_PATH"/%s/batman_adv/mesh_iface" -#define SYS_IFACE_STATUS_FMT SYS_IFACE_PATH"/%s/batman_adv/iface_status" +#define SYS_BATIF_PATH_FMT "/sys/class/net/%s/mesh/" +#define SYS_LOG_LEVEL "log_level" +#define SYS_LOG "log" +#define SYS_GW_MODE "gw_mode" +#define SYS_GW_SEL "gw_sel_class" +#define SYS_GW_BW "gw_bandwidth" +#define SYS_IFACE_PATH "/sys/class/net" +#define SYS_IFACE_DIR SYS_IFACE_PATH"/%s/" +#define SYS_MESH_IFACE_FMT SYS_IFACE_PATH"/%s/batman_adv/mesh_iface" +#define SYS_IFACE_STATUS_FMT SYS_IFACE_PATH"/%s/batman_adv/iface_status" +#define SYS_VLAN_PATH SYS_IFACE_PATH"/%s/mesh/vlan%d/" +#define VLAN_ID_MAX_LEN 4enum batctl_settings_list {BATCTL_SETTINGS_ORIG_INTERVAL ,
Signature · 1 line
1.8.5.2
Quoted 18 lines · On Sunday 05 January 2014 09:59:52 Antonio Quartulli wrote:
functions.c +6
-1@@ -528,7 +526,7 @@ static int resolve_mac_from_cache_open(int ai_family)if (ret <0 ) goto outclose; - ret =send (socknl, &nlreq, nlreq.hdr.nlmsg_len,0 ); + ret =send (socknl, req, len,0 );if (ret <0 ) goto outclose; out:@@ -538,6 +536,22 @@ outclose:return ret; } +static int resolve_mac_from_cache_open (int ai_family) +{ +struct { +struct nlmsghdr hdr; +struct ndmsg msg;
functions.c outclose: · line 553
Quoted 10 lines
functions.c +10
-0+ } nlreq; + +memset (&nlreq,0 ,sizeof (nlreq)); + nlreq.hdr.nlmsg_len =NLMSG_LENGTH (sizeof (nlreq.msg)); + nlreq.hdr.nlmsg_type =RTM_GETNEIGH ; + nlreq.hdr.nlmsg_flags =NLM_F_REQUEST |NLM_F_DUMP ; + nlreq.msg.ndm_family = ai_family; + +return rtnl_open (&nlreq,sizeof (nlreq),NETLINK_ROUTE ); +}
Is 'sizeof(nlreq)' equal to 'nlreq.hdr.nlmsg_len' ? It seems not ...
Cheers,
Marek
Quoted 23 lines · Marek Lindner
Quoted 22 lines · On Sunday 05 January 2014 09:59:52 Antonio Quartulli wrote:
functions.c +10
-1@@ -528,7 +526,7 @@ static int resolve_mac_from_cache_open(int ai_family)if (ret <0 ) goto outclose; - ret =send (socknl, &nlreq, nlreq.hdr.nlmsg_len,0 ); + ret =send (socknl, req, len,0 );if (ret <0 ) goto outclose; out:@@ -538,6 +536,22 @@ outclose:return ret; } +static int resolve_mac_from_cache_open (int ai_family) +{ +struct { +struct nlmsghdr hdr; +struct ndmsg msg; + } nlreq; + +memset (&nlreq,0 ,sizeof (nlreq)); + nlreq.hdr.nlmsg_len =NLMSG_LENGTH (sizeof (nlreq.msg));
Quoted 8 lines
functions.c outclose: · line 553
Quoted 6 lines
functions.c +6
-0+ nlreq.hdr.nlmsg_type =RTM_GETNEIGH ; + nlreq.hdr.nlmsg_flags =NLM_F_REQUEST |NLM_F_DUMP ; + nlreq.msg.ndm_family = ai_family; + +return rtnl_open (&nlreq,sizeof (nlreq),NETLINK_ROUTE ); +}Is 'sizeof(nlreq)' equal to 'nlreq.hdr.nlmsg_len' ? It seems not ...
It is because the macro NLMSG_LENGTH adds NLMSG_HDRLEN to the value passed as argument (in this case it is sizeof(nlreq.msg)) and therefore what we store in nlreq.hdr.nlmsg_len is sizeof(nlreq) (plus some possible alignment bytes).
I think I can make it more clear and always pass nlreq.hdr.nlmsg_len to send().
Thanks!
v2 is coming!
Cheers,
Signature · 1 line
Antonio Quartulli