summaryrefslogtreecommitdiff
path: root/accel-pppd
diff options
context:
space:
mode:
authorDmitry Kozlov <xeb@mail.ru>2015-11-21 12:34:02 +0300
committerDmitry Kozlov <xeb@mail.ru>2015-11-21 12:34:02 +0300
commit9190fe47e0ce57e8f0b3360f2fe0404169b44263 (patch)
treef774de35c1895fa6b4a9b20ac65930d7675c23bc /accel-pppd
parentdecb3de44c59f789e49250c4d2791e4219078b54 (diff)
downloadaccel-ppp-9190fe47e0ce57e8f0b3360f2fe0404169b44263.tar.gz
accel-ppp-9190fe47e0ce57e8f0b3360f2fe0404169b44263.zip
split ipoe driver to ipoe and vlan_mon
introduced new module "vlan-mon"
Diffstat (limited to 'accel-pppd')
-rw-r--r--accel-pppd/CMakeLists.txt1
-rw-r--r--accel-pppd/accel-ppp.conf1
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.c66
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.h4
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe_netlink.c139
-rw-r--r--accel-pppd/include/vlan_mon.h15
-rw-r--r--accel-pppd/vlan-mon/CMakeLists.txt8
l---------accel-pppd/vlan-mon/if_vlan_mon.h1
-rw-r--r--accel-pppd/vlan-mon/vlan_mon.c348
9 files changed, 393 insertions, 190 deletions
diff --git a/accel-pppd/CMakeLists.txt b/accel-pppd/CMakeLists.txt
index aa13e55..ab96bc0 100644
--- a/accel-pppd/CMakeLists.txt
+++ b/accel-pppd/CMakeLists.txt
@@ -32,6 +32,7 @@ ENDIF (RADIUS)
ADD_SUBDIRECTORY(triton)
+ADD_SUBDIRECTORY(vlan-mon)
ADD_SUBDIRECTORY(ctrl)
ADD_SUBDIRECTORY(auth)
ADD_SUBDIRECTORY(logs)
diff --git a/accel-pppd/accel-ppp.conf b/accel-pppd/accel-ppp.conf
index 81d176d..70dbef8 100644
--- a/accel-pppd/accel-ppp.conf
+++ b/accel-pppd/accel-ppp.conf
@@ -25,6 +25,7 @@ pppd_compat
#net-snmp
#logwtmp
#connlimit
+#vlan-mon
#ipv6_nd
#ipv6_dhcp
diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c
index 594df29..d77da31 100644
--- a/accel-pppd/ctrl/ipoe/ipoe.c
+++ b/accel-pppd/ctrl/ipoe/ipoe.c
@@ -33,6 +33,7 @@
#include "ipset.h"
#include "connlimit.h"
+#include "vlan_mon.h"
#include "ipoe.h"
@@ -2082,7 +2083,7 @@ static void ipoe_serv_release(struct ipoe_serv *serv)
if (serv->vid) {
log_info2("ipoe: remove vlan %s\n", serv->ifname);
iplink_vlan_del(serv->ifindex);
- ipoe_nl_add_vlan_mon_vid(serv->parent_ifindex, serv->vid);
+ vlan_mon_add_vid(serv->parent_ifindex, ETH_P_IP, serv->vid);
}
triton_context_unregister(&serv->ctx);
@@ -2205,43 +2206,7 @@ static int get_offer_delay()
return 0;
}
-static int make_vlan_name(const char *parent, int svid, int cvid, char *name)
-{
- char *ptr1 = name, *endptr = name + IFNAMSIZ;
- const char *ptr2 = conf_vlan_name;
- char svid_str[5], cvid_str[5], *ptr3;
-
- sprintf(svid_str, "%i", svid);
- sprintf(cvid_str, "%i", cvid);
-
- while (ptr1 < endptr && *ptr2) {
- if (ptr2[0] == '%' && ptr2[1] == 'I') {
- while (ptr1 < endptr && *parent)
- *ptr1++ = *parent++;
- ptr2 += 2;
- } else if (ptr2[0] == '%' && ptr2[1] == 'N') {
- ptr3 = cvid_str;
- while (ptr1 < endptr && *ptr3)
- *ptr1++ = *ptr3++;
- ptr2 += 2;
- } else if (ptr2[0] == '%' && ptr2[1] == 'P') {
- ptr3 = svid_str;
- while (ptr1 < endptr && *ptr3)
- *ptr1++ = *ptr3++;
- ptr2 += 2;
- } else
- *ptr1++ = *ptr2++;
- }
-
- if (ptr1 == endptr)
- return 1;
-
- *ptr1 = 0;
-
- return 0;
-}
-
-void ipoe_vlan_notify(int ifindex, int vid)
+void ipoe_vlan_mon_notify(int ifindex, int vid)
{
struct conf_sect_t *sect = conf_get_section("ipoe");
struct conf_option_t *opt;
@@ -2266,20 +2231,18 @@ void ipoe_vlan_notify(int ifindex, int vid)
svid = iplink_vlan_get_vid(ifindex);
- if (make_vlan_name(ifr.ifr_name, svid, vid, ifname)) {
+ if (make_vlan_name(conf_vlan_name, ifr.ifr_name, svid, vid, ifname)) {
log_error("ipoe: vlan-mon: %s.%i: interface name is too long\n", ifr.ifr_name, vid);
return;
}
- log_info2("ipoe: create vlan %s parent %s\n", ifname, ifr.ifr_name);
-
strcpy(ifr.ifr_name, ifname);
len = strlen(ifr.ifr_name);
- if (iplink_vlan_add(ifr.ifr_name, ifindex, vid)) {
- log_warn("ipoe: vlan-mon: %s: failed to add vlan\n", ifr.ifr_name);
+ if (iplink_vlan_add(ifr.ifr_name, ifindex, vid))
return;
- }
+
+ log_info2("ipoe: create vlan %s parent %s\n", ifname, ifr.ifr_name);
ioctl(sock_fd, SIOCGIFFLAGS, &ifr, sizeof(ifr));
ifr.ifr_flags |= IFF_UP;
@@ -3012,7 +2975,7 @@ static void add_vlan_mon(const char *opt, long *mask)
mask1[serv->vid / (8*sizeof(long))] |= 1lu << (serv->vid % (8*sizeof(long)));
}
- ipoe_nl_add_vlan_mon(ifindex, mask1, sizeof(mask1));
+ vlan_mon_add(ifindex, ETH_P_IP, mask1, sizeof(mask1));
}
static int __load_vlan_mon_re(int index, int flags, const char *name, struct iplink_arg *arg)
@@ -3041,7 +3004,7 @@ static int __load_vlan_mon_re(int index, int flags, const char *name, struct ipl
mask1[serv->vid / (8*sizeof(long))] |= 1lu << (serv->vid % (8*sizeof(long)));
}
- ipoe_nl_add_vlan_mon(index, mask1, sizeof(mask1));
+ vlan_mon_add(index, ETH_P_IP, mask1, sizeof(mask1));
return 0;
}
@@ -3083,8 +3046,17 @@ static void load_vlan_mon(struct conf_sect_t *sect)
{
struct conf_option_t *opt;
long mask[4096/8/sizeof(long)];
+ static int registered = 0;
+
+ if (!triton_module_loaded("vlan-mon"))
+ return;
+
+ if (!registered) {
+ vlan_mon_register_proto(ETH_P_IP, ipoe_vlan_mon_notify);
+ registered = 1;
+ }
- ipoe_nl_del_vlan_mon(-1);
+ vlan_mon_del(-1, ETH_P_IP);
list_for_each_entry(opt, &sect->items, entry) {
if (strcmp(opt->name, "vlan-mon"))
diff --git a/accel-pppd/ctrl/ipoe/ipoe.h b/accel-pppd/ctrl/ipoe/ipoe.h
index 1405092..224b9e9 100644
--- a/accel-pppd/ctrl/ipoe/ipoe.h
+++ b/accel-pppd/ctrl/ipoe/ipoe.h
@@ -114,7 +114,6 @@ struct iphdr;
struct ethhdr;
void ipoe_recv_up(int ifindex, struct ethhdr *eth, struct iphdr *iph);
-void ipoe_vlan_notify(int ifindex, int vid);
struct ipoe_session *ipoe_session_alloc(void);
@@ -128,9 +127,6 @@ int ipoe_nl_create(uint32_t peer_addr, uint32_t addr, const char *ifname, uint8_
void ipoe_nl_delete(int ifindex);
int ipoe_nl_modify(int ifindex, uint32_t peer_addr, uint32_t addr, const char *ifname, uint8_t *hwaddr);
void ipoe_nl_get_sessions(struct list_head *list);
-int ipoe_nl_add_vlan_mon(int ifindex, long *mask, int len);
-int ipoe_nl_add_vlan_mon_vid(int ifindex, int vid);
-int ipoe_nl_del_vlan_mon(int ifindex);
int ipoe_nl_add_exclude(uint32_t addr, int mask);
void ipoe_nl_del_exclude(uint32_t addr);
diff --git a/accel-pppd/ctrl/ipoe/ipoe_netlink.c b/accel-pppd/ctrl/ipoe/ipoe_netlink.c
index c061036..18542cd 100644
--- a/accel-pppd/ctrl/ipoe/ipoe_netlink.c
+++ b/accel-pppd/ctrl/ipoe/ipoe_netlink.c
@@ -448,106 +448,6 @@ void ipoe_nl_delete(int ifindex)
rtnl_close(&rth);
}
-int ipoe_nl_add_vlan_mon(int ifindex, long *mask, int len)
-{
- struct nlmsghdr *nlh;
- struct genlmsghdr *ghdr;
- struct {
- struct nlmsghdr n;
- char buf[1024];
- } req;
-
- if (rth.fd == -1)
- return -1;
-
- nlh = &req.n;
- nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
- nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
- nlh->nlmsg_type = ipoe_genl_id;
-
- ghdr = NLMSG_DATA(&req.n);
- ghdr->cmd = IPOE_CMD_ADD_VLAN_MON;
-
- addattr32(nlh, 1024, IPOE_ATTR_IFINDEX, ifindex);
- addattr_l(nlh, 1024, IPOE_ATTR_VLAN_MASK, mask, len);
-
- if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) {
- log_error("ipoe: nl_add_vlan_mon: error talking to kernel\n");
- return -1;
- }
-
- return 0;
-}
-
-int ipoe_nl_add_vlan_mon_vid(int ifindex, int vid)
-{
- struct rtnl_handle rth;
- struct nlmsghdr *nlh;
- struct genlmsghdr *ghdr;
- struct {
- struct nlmsghdr n;
- char buf[1024];
- } req;
- int r = 0;
-
- if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC)) {
- log_error("ipoe: cannot open generic netlink socket\n");
- return -1;
- }
-
- nlh = &req.n;
- nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
- nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
- nlh->nlmsg_type = ipoe_genl_id;
-
- ghdr = NLMSG_DATA(&req.n);
- ghdr->cmd = IPOE_CMD_ADD_VLAN_MON_VID;
-
- addattr32(nlh, 1024, IPOE_ATTR_IFINDEX, ifindex);
- addattr32(nlh, 1024, IPOE_ATTR_ADDR, vid);
-
- if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) {
- log_error("ipoe: nl_add_vlan_mon_vid: error talking to kernel\n");
- r = -1;
- }
-
- rtnl_close(&rth);
-
- return r;
-}
-
-
-int ipoe_nl_del_vlan_mon(int ifindex)
-{
- struct nlmsghdr *nlh;
- struct genlmsghdr *ghdr;
- struct {
- struct nlmsghdr n;
- char buf[1024];
- } req;
-
- if (rth.fd == -1)
- return -1;
-
- nlh = &req.n;
- nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
- nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
- nlh->nlmsg_type = ipoe_genl_id;
-
- ghdr = NLMSG_DATA(&req.n);
- ghdr->cmd = IPOE_CMD_DEL_VLAN_MON;
-
- addattr32(nlh, 1024, IPOE_ATTR_IFINDEX, ifindex);
-
- if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) {
- log_error("ipoe: nl_del_vlan_mon: error talking to kernel\n");
- return -1;
- }
-
- return 0;
-}
-
-
static void ipoe_up_handler(const struct sockaddr_nl *addr, struct nlmsghdr *h)
{
struct rtattr *tb[PKT_ATTR_MAX + 1];
@@ -587,43 +487,6 @@ static void ipoe_up_handler(const struct sockaddr_nl *addr, struct nlmsghdr *h)
}
}
-static void ipoe_vlan_mon_handler(const struct sockaddr_nl *addr, struct nlmsghdr *h)
-{
- struct rtattr *tb[PKT_ATTR_MAX + 1];
- struct rtattr *tb2[IPOE_ATTR_MAX + 1];
- struct genlmsghdr *ghdr = NLMSG_DATA(h);
- int len = h->nlmsg_len;
- struct rtattr *attrs;
- int i;
- int ifindex, vid;
-
- len -= NLMSG_LENGTH(GENL_HDRLEN);
-
- if (len < 0) {
- log_warn("ipoe: wrong controller message length %d\n", len);
- return;
- }
-
- attrs = (struct rtattr *)((char *)ghdr + GENL_HDRLEN);
- parse_rtattr(tb, PKT_ATTR_MAX, attrs, len);
-
- for (i = 1; i < PKT_ATTR_MAX; i++) {
- if (!tb[i])
- break;
-
- parse_rtattr_nested(tb2, IPOE_ATTR_MAX, tb[i]);
-
- if (!tb2[IPOE_ATTR_IFINDEX] || !tb2[IPOE_ATTR_ADDR])
- continue;
-
- ifindex = *(uint32_t *)(RTA_DATA(tb2[IPOE_ATTR_IFINDEX]));
- vid = *(uint32_t *)(RTA_DATA(tb2[IPOE_ATTR_ADDR]));
-
- ipoe_vlan_notify(ifindex, vid);
- }
-}
-
-
static int ipoe_mc_read(struct triton_md_handler_t *h)
{
int status;
@@ -685,8 +548,6 @@ static int ipoe_mc_read(struct triton_md_handler_t *h)
if (ghdr->cmd == IPOE_REP_PKT)
ipoe_up_handler(&nladdr, hdr);
- else if (ghdr->cmd == IPOE_VLAN_NOTIFY)
- ipoe_vlan_mon_handler(&nladdr, hdr);
status -= NLMSG_ALIGN(len);
hdr = (struct nlmsghdr*)((char*)hdr + NLMSG_ALIGN(len));
diff --git a/accel-pppd/include/vlan_mon.h b/accel-pppd/include/vlan_mon.h
new file mode 100644
index 0000000..928c732
--- /dev/null
+++ b/accel-pppd/include/vlan_mon.h
@@ -0,0 +1,15 @@
+#ifndef __VLAN_MON_H
+#define __VLAN_MON_H
+
+typedef void (*vlan_mon_notify)(int ifindex, int vid);
+
+void vlan_mon_register_proto(int proto, vlan_mon_notify cb);
+
+int vlan_mon_add(int ifindex, int proto, long *mask, int len);
+int vlan_mon_add_vid(int ifindex, int proto, int vid);
+int vlan_mon_del(int ifindex, int proto);
+
+int make_vlan_name(const char *pattern, const char *parent, int svid, int cvid, char *name);
+
+
+#endif
diff --git a/accel-pppd/vlan-mon/CMakeLists.txt b/accel-pppd/vlan-mon/CMakeLists.txt
new file mode 100644
index 0000000..1305825
--- /dev/null
+++ b/accel-pppd/vlan-mon/CMakeLists.txt
@@ -0,0 +1,8 @@
+#INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+
+ADD_LIBRARY(vlan-mon SHARED vlan_mon.c)
+
+INSTALL(TARGETS vlan-mon
+ LIBRARY DESTINATION lib${LIB_SUFFIX}/accel-ppp
+)
+
diff --git a/accel-pppd/vlan-mon/if_vlan_mon.h b/accel-pppd/vlan-mon/if_vlan_mon.h
new file mode 120000
index 0000000..a1ad472
--- /dev/null
+++ b/accel-pppd/vlan-mon/if_vlan_mon.h
@@ -0,0 +1 @@
+../../drivers/vlan_mon/vlan_mon.h \ No newline at end of file
diff --git a/accel-pppd/vlan-mon/vlan_mon.c b/accel-pppd/vlan-mon/vlan_mon.c
new file mode 100644
index 0000000..898d7dc
--- /dev/null
+++ b/accel-pppd/vlan-mon/vlan_mon.c
@@ -0,0 +1,348 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/ethernet.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+#include <linux/if.h>
+#include <linux/genetlink.h>
+
+#include "triton.h"
+#include "log.h"
+#include "genl.h"
+#include "libnetlink.h"
+#include "iputils.h"
+
+#include "vlan_mon.h"
+#include "if_vlan_mon.h"
+
+#include "memdebug.h"
+
+#define PKT_ATTR_MAX 256
+
+static struct rtnl_handle rth;
+static struct triton_md_handler_t mc_hnd;
+static int vlan_mon_genl_id;
+
+static vlan_mon_notify cb[2];
+
+static void init(void);
+
+void __export vlan_mon_register_proto(int proto, vlan_mon_notify func)
+{
+ if (proto == ETH_P_PPP_DISC)
+ proto = 1;
+ else
+ proto = 0;
+
+ cb[proto] = func;
+
+ if (!vlan_mon_genl_id)
+ init();
+}
+
+int __export vlan_mon_add(int ifindex, int proto, long *mask, int len)
+{
+ struct nlmsghdr *nlh;
+ struct genlmsghdr *ghdr;
+ struct {
+ struct nlmsghdr n;
+ char buf[1024];
+ } req;
+
+ if (rth.fd == -1)
+ return -1;
+
+ nlh = &req.n;
+ nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ nlh->nlmsg_type = vlan_mon_genl_id;
+
+ ghdr = NLMSG_DATA(&req.n);
+ ghdr->cmd = VLAN_MON_CMD_ADD;
+
+ addattr32(nlh, 1024, VLAN_MON_ATTR_IFINDEX, ifindex);
+ addattr_l(nlh, 1024, VLAN_MON_ATTR_VLAN_MASK, mask, len);
+ addattr32(nlh, 1024, VLAN_MON_ATTR_PROTO, proto);
+
+ if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) {
+ log_error("vlan_mon: nl_add_vlan_mon: error talking to kernel\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int __export vlan_mon_add_vid(int ifindex, int proto, int vid)
+{
+ struct nlmsghdr *nlh;
+ struct genlmsghdr *ghdr;
+ struct {
+ struct nlmsghdr n;
+ char buf[1024];
+ } req;
+ int r = 0;
+
+ if (rth.fd == -1)
+ return -1;
+
+ nlh = &req.n;
+ nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ nlh->nlmsg_type = vlan_mon_genl_id;
+
+ ghdr = NLMSG_DATA(&req.n);
+ ghdr->cmd = VLAN_MON_CMD_ADD_VID;
+
+ addattr32(nlh, 1024, VLAN_MON_ATTR_IFINDEX, ifindex);
+ addattr32(nlh, 1024, VLAN_MON_ATTR_VID, vid);
+ addattr32(nlh, 1024, VLAN_MON_ATTR_PROTO, proto);
+
+ if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) {
+ log_error("vlan_mon: nl_add_vlan_mon_vid: error talking to kernel\n");
+ r = -1;
+ }
+
+ return r;
+}
+
+int __export vlan_mon_del(int ifindex, int proto)
+{
+ struct nlmsghdr *nlh;
+ struct genlmsghdr *ghdr;
+ struct {
+ struct nlmsghdr n;
+ char buf[1024];
+ } req;
+
+ if (rth.fd == -1)
+ return -1;
+
+ nlh = &req.n;
+ nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ nlh->nlmsg_type = vlan_mon_genl_id;
+
+ ghdr = NLMSG_DATA(&req.n);
+ ghdr->cmd = VLAN_MON_CMD_DEL;
+
+ addattr32(nlh, 1024, VLAN_MON_ATTR_IFINDEX, ifindex);
+ addattr32(nlh, 1024, VLAN_MON_ATTR_PROTO, proto);
+
+ if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) {
+ log_error("vlan_mon: nl_del_vlan_mon: error talking to kernel\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void vlan_mon_handler(const struct sockaddr_nl *addr, struct nlmsghdr *h)
+{
+ struct rtattr *tb[PKT_ATTR_MAX + 1];
+ struct rtattr *tb2[VLAN_MON_ATTR_MAX + 1];
+ struct genlmsghdr *ghdr = NLMSG_DATA(h);
+ int len = h->nlmsg_len;
+ struct rtattr *attrs;
+ int i;
+ int ifindex, vid, proto;
+
+ len -= NLMSG_LENGTH(GENL_HDRLEN);
+
+ if (len < 0) {
+ log_warn("vlan_mon: wrong controller message length %d\n", len);
+ return;
+ }
+
+ attrs = (struct rtattr *)((char *)ghdr + GENL_HDRLEN);
+ parse_rtattr(tb, PKT_ATTR_MAX, attrs, len);
+
+ for (i = 1; i < PKT_ATTR_MAX; i++) {
+ if (!tb[i])
+ break;
+
+ parse_rtattr_nested(tb2, VLAN_MON_ATTR_MAX, tb[i]);
+
+ //if (!tb2[VLAN_MON_ATTR_IFINDEX] || !tb2[VLAN_MON_ATTR_VID] || !t)
+ // continue;
+
+ ifindex = *(uint32_t *)(RTA_DATA(tb2[VLAN_MON_ATTR_IFINDEX]));
+ vid = *(uint32_t *)(RTA_DATA(tb2[VLAN_MON_ATTR_VID]));
+ proto = *(uint32_t *)(RTA_DATA(tb2[VLAN_MON_ATTR_PROTO]));
+
+ log_debug("vlan-mon: notify %i %i %04x\n", ifindex, vid, proto);
+
+ if (proto == ETH_P_PPP_DISC)
+ proto = 1;
+ else
+ proto = 0;
+
+ if (cb[proto])
+ cb[proto](ifindex, vid);
+ }
+}
+
+
+static int vlan_mon_mc_read(struct triton_md_handler_t *h)
+{
+ int status;
+ struct nlmsghdr *hdr;
+ struct genlmsghdr *ghdr;
+ struct sockaddr_nl nladdr;
+ struct iovec iov;
+ struct msghdr msg = {
+ .msg_name = &nladdr,
+ .msg_namelen = sizeof(nladdr),
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ };
+ char buf[8192];
+
+ memset(&nladdr, 0, sizeof(nladdr));
+ nladdr.nl_family = AF_NETLINK;
+ nladdr.nl_pid = 0;
+ nladdr.nl_groups = 0;
+
+ iov.iov_base = buf;
+ while (1) {
+ iov.iov_len = sizeof(buf);
+ status = recvmsg(h->fd, &msg, 0);
+
+ if (status < 0) {
+ if (errno == EAGAIN)
+ break;
+ log_error("vlan_mon: netlink error: %s\n", strerror(errno));
+ if (errno == ENOBUFS)
+ continue;
+ return 0;
+ }
+
+ if (status == 0) {
+ log_error("vlan_mon: EOF on netlink\n");
+ return 0;
+ }
+
+ if (msg.msg_namelen != sizeof(nladdr)) {
+ log_error("vlan_mon: netlink sender address length == %d\n", msg.msg_namelen);
+ return 0;
+ }
+
+ for (hdr = (struct nlmsghdr*)buf; status >= sizeof(*hdr); ) {
+ int len = hdr->nlmsg_len;
+ int l = len - sizeof(*h);
+
+ if (l<0 || len>status) {
+ if (msg.msg_flags & MSG_TRUNC) {
+ log_warn("vlan_mon: truncated netlink message\n");
+ continue;
+ }
+ log_error("vlan_mon: malformed netlink message\n");
+ continue;
+ }
+
+ ghdr = NLMSG_DATA(hdr);
+
+ if (ghdr->cmd == VLAN_MON_NOTIFY)
+ vlan_mon_handler(&nladdr, hdr);
+
+ status -= NLMSG_ALIGN(len);
+ hdr = (struct nlmsghdr*)((char*)hdr + NLMSG_ALIGN(len));
+ }
+
+ if (msg.msg_flags & MSG_TRUNC) {
+ log_warn("vlan_mon: netlink message truncated\n");
+ continue;
+ }
+
+ if (status) {
+ log_error("vlan_mon: netlink remnant of size %d\n", status);
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+int __export make_vlan_name(const char *pattern, const char *parent, int svid, int cvid, char *name)
+{
+ char *ptr1 = name, *endptr = name + IFNAMSIZ;
+ const char *ptr2 = pattern;
+ char svid_str[5], cvid_str[5], *ptr3;
+
+ sprintf(svid_str, "%i", svid);
+ sprintf(cvid_str, "%i", cvid);
+
+ while (ptr1 < endptr && *ptr2) {
+ if (ptr2[0] == '%' && ptr2[1] == 'I') {
+ while (ptr1 < endptr && *parent)
+ *ptr1++ = *parent++;
+ ptr2 += 2;
+ } else if (ptr2[0] == '%' && ptr2[1] == 'N') {
+ ptr3 = cvid_str;
+ while (ptr1 < endptr && *ptr3)
+ *ptr1++ = *ptr3++;
+ ptr2 += 2;
+ } else if (ptr2[0] == '%' && ptr2[1] == 'P') {
+ ptr3 = svid_str;
+ while (ptr1 < endptr && *ptr3)
+ *ptr1++ = *ptr3++;
+ ptr2 += 2;
+ } else
+ *ptr1++ = *ptr2++;
+ }
+
+ if (ptr1 == endptr)
+ return 1;
+
+ *ptr1 = 0;
+
+ return 0;
+}
+
+
+static void vlan_mon_mc_close(struct triton_context_t *ctx)
+{
+ triton_md_unregister_handler(&mc_hnd, 0);
+ triton_context_unregister(ctx);
+}
+
+static struct triton_context_t mc_ctx = {
+ .close = vlan_mon_mc_close,
+};
+
+static struct triton_md_handler_t mc_hnd = {
+ .read = vlan_mon_mc_read,
+};
+
+static void init(void)
+{
+ int mcg_id = genl_resolve_mcg(VLAN_MON_GENL_NAME, VLAN_MON_GENL_MCG, &vlan_mon_genl_id);
+ if (mcg_id == -1) {
+ log_warn("vlan_mon: kernel module is not loaded\n");
+ rth.fd = -1;
+ vlan_mon_genl_id = -1;
+ return;
+ }
+
+ if (rtnl_open_byproto(&rth, 1 << (mcg_id - 1), NETLINK_GENERIC)) {
+ log_error("vlan_mon: cannot open generic netlink socket\n");
+ rth.fd = -1;
+ return;
+ }
+
+ fcntl(rth.fd, F_SETFL, O_NONBLOCK);
+ fcntl(rth.fd, F_SETFD, fcntl(rth.fd, F_GETFD) | FD_CLOEXEC);
+
+ triton_context_register(&mc_ctx, NULL);
+ mc_hnd.fd = rth.fd;
+ triton_md_register_handler(&mc_ctx, &mc_hnd);
+ triton_md_enable_handler(&mc_hnd, MD_MODE_READ);
+ triton_context_wakeup(&mc_ctx);
+}
+