batctl: introduce rtnl_open() helper function
PATCH v2 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.
---
Changes from v1:
- fixed typ0
- removed len argument from rtnl_open() in 1/3
- removed error messages in 2/3
- avoided double free in 2/3
- simplified 3/3
functions.c | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-)
functions.c +29 -16
@@ -497,30 +497,27 @@ 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 +* @nh: the header of the request to send +* @protocol: the protocol to use when opening the socket +* +* Return 0 on success or a negative error code otherwise +*/ +static int rtnl_open (struct nlmsghdr *nh,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 +525,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, nh, nh->nlmsg_len,0 );if (ret <0 ) goto outclose; out:
@@ -538,6 +535,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.hdr,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 v2 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 | 165 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ functions.h | 1 + 2 files changed, 166 insertions(+)
functions.c +165 -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"
@@ -764,3 +765,167 @@ 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" )) + 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 ) + goto err; + +if (idx <=0 ) + 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: 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 sockaddr_nl nladdr; +struct msghdr msg; +struct iovec iov; + +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; + +return recvmsg (sock, &msg,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 NLMSG 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.hdr,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
PATCH v2 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.
--- main.c | 2 +- man/batctl.8 | 4 ++-- sys.c | 15 +++++++++++++-- sys.h | 22 ++++++++++++---------- 4 files changed, 28 insertions(+), 15 deletions(-)
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 VLAN created on top of a mesh 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 VLAN created on top of a mesh 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 +13 -2
@@ -372,8 +372,8 @@ static void settings_usage(int setting)int handle_sys_setting (char *mesh_iface,int setting,int argc,char **argv) { -int optchar, res =EXIT_FAILURE ; -char *path_buff; +int vid, optchar, res =EXIT_FAILURE ; +char *path_buff, *base_dev =NULL ;const char **ptr;while ((optchar =getopt (argc, argv,"h" )) !=-1 ) {
@@ -387,10 +387,20 @@ int handle_sys_setting(char *mesh_iface, int setting, int argc, char **argv) } } +/* prepare the classic path */ path_buff =malloc (PATH_BUFF_LEN );snprintf (path_buff,PATH_BUFF_LEN ,SYS_BATIF_PATH_FMT , mesh_iface); path_buff[PATH_BUFF_LEN -1 ] ='\0' ; +/* if the specified interface is a VLAN then change the path to point +* to the proper "vlan%{vid}" subfolder in the sysfs tree. +*/ + vid =vlan_get_link (mesh_iface, &base_dev); +if (vid >=0 ) { +snprintf (path_buff,PATH_BUFF_LEN ,SYS_VLAN_PATH , base_dev, vid); + path_buff[PATH_BUFF_LEN -1 ] ='\0' ; + } +if (argc ==1 ) { res =read_file (path_buff, (char *)batctl_settings[setting].sysfs_name,NO_FLAGS ,0 ,0 ,0 );
@@ -425,6 +435,7 @@ write_file: out:free (path_buff); +free (base_dev);return res; }
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