Hi,

I would like to easily match a set of dynamically created interfaces
from my packet filter rules. The attached patch forms the basis of my
implementation and I would like to know whether something like this is
mergeable to mainline.

The use-case is as follows:

* I have two different subsystems creating interfaces dynamically (for
example pptpd and serial pppd lines, each creating dynamic pppX
interfaces),
* I would like to assign a different set of iptables rules for these
clients,
* I would like to react to a new interface being added to a specific set
in a userspace application,

The reasons I see this needs new kernel functionality:

* iptables supports wildcard interface matching (for example "iptables
-i ppp+"), but as the names of the interfaces used by PPTPD and PPPD
cannot be distinguished this way, this is not enough,
* Reloading the iptables ruleset everytime a new interface comes up is
not really feasible, as it abrupts packet processing, and validating the
ruleset in the kernel can take significant amount of time,
* the kernel change is very simple, adapting userspace to this change is
also very simple, and in userspace various software packages can easily
interoperate with each-other once this is merged.

The implementation:

Each interface can belong to a single "group" at a time, an interface
comes up without being a member in any of the groups.

Userspace can assign interfaces to groups after being created, this
would typically be performed in /etc/ppp/ip-up.d (and similar) scripts.

In spirit "interface group" is somewhat similar to the "routing
protocol" field for routing entries, which contains information on which
routing daemon was responsible for adding the given route entry.

Things to be done if you like this approach:

* interface group match in iptables,
* support for naming interface groups in userspace, a'la routing
protocols,
* emitting a netlink notification when the group of an interface
changes,
* possibly converting the "ip link" command to use NETLINK messages,
instead of using ioctl()

What do you think?

kernel patch:
-------------

* add a numeric ID to each interface in the system, denoting its
"interface group",


index df0cdd4..19a103a 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -736,6 +736,8 @@ enum
 #define IFLA_WEIGHT IFLA_WEIGHT
        IFLA_OPERSTATE,
        IFLA_LINKMODE,
+#define IFLA_IFGROUP IFLA_IFGROUP
+       IFLA_IFGROUP,
        __IFLA_MAX
 };

diff --git a/include/linux/sockios.h b/include/linux/sockios.h
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 3fcfa9c..26849af 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -279,6 +279,11 @@ static int rtnetlink_fill_ifinfo(struct
                u32 iflink = dev->iflink;
                RTA_PUT(skb, IFLA_LINK, sizeof(iflink), &iflink);
        }
+
+       if (dev->ifgroup) {
+               u32 ifgroup = dev->ifgroup;
+               RTA_PUT(skb, IFLA_IFGROUP, sizeof(ifgroup), &ifgroup);
+       }

        if (dev->qdisc_sleeping)
                RTA_PUT(skb, IFLA_QDISC,
@@ -459,6 +464,12 @@ static int do_setlink(struct sk_buff *sk
                dev->link_mode = *((u8 *) RTA_DATA(ida[IFLA_LINKMODE - 1]));
                write_unlock_bh(&dev_base_lock);
        }
+
+       if (ida[IFLA_IFGROUP - 1]) {
+               if (ida[IFLA_IFGROUP - 1]->rta_len != RTA_LENGTH(sizeof(u32)))
+                       goto out;
+               dev->ifgroup = *((u32 *) RTA_DATA(ida[IFLA_IFGROUP - 1]));
+       }

        if (ifm->ifi_index >= 0 && ida[IFLA_IFNAME - 1]) {
                char ifname[IFNAMSIZ];


ip route patch:
---------------

* added a "group" option to ip link set to make it possible to set this
id, and a way to print this option


diff --git a/ip/iplink.c b/ip/iplink.c
index ffc9f06..e694475 100644
--- a/ip/iplink.c
+++ b/ip/iplink.c
@@ -26,6 +26,7 @@
 #include <string.h>
 #include <sys/ioctl.h>
 #include <linux/sockios.h>
+#include <linux/rtnetlink.h>

 #include "rt_names.h"
 #include "utils.h"
@@ -44,6 +45,7 @@ void iplink_usage(void)
        fprintf(stderr, "                            promisc { on | off } |\n");
        fprintf(stderr, "                            trailers { on | off } 
|\n");
        fprintf(stderr, "                            txqueuelen PACKETS |\n");
+       fprintf(stderr, "                            group GROUP |\n");
        fprintf(stderr, "                            name NEWNAME |\n");
        fprintf(stderr, "                            address LLADDR | broadcast 
LLADDR |\n");
        fprintf(stderr, "                            mtu MTU }\n");
@@ -174,6 +176,28 @@ static int set_mtu(const char *dev, int
        return 0;
 }

+static int set_group(const char *dev, int ifgroup)
+{
+       struct {
+               struct nlmsghdr         n;
+               struct ifinfomsg        ifi;
+               char                    buf[256];
+       } req;
+
+       memset(&req, 0, sizeof(req));
+       req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifi));
+       req.n.nlmsg_flags = NLM_F_REQUEST;
+       req.n.nlmsg_type = RTM_SETLINK;
+
+       req.ifi.ifi_index = -1;
+
+       addattr_l(&req.n, sizeof(req), IFLA_IFNAME, dev, strlen(dev)+1);
+       addattr_l(&req.n, sizeof(req), IFLA_IFGROUP, &ifgroup, sizeof(ifgroup));
+       if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
+               return -1;
+       return 0;
+}
+
 static int get_address(const char *dev, int *htype)
 {
        struct ifreq ifr;
@@ -257,6 +281,7 @@ static int do_set(int argc, char **argv)
        __u32 mask = 0;
        __u32 flags = 0;
        int qlen = -1;
+       int group = 0;
        int mtu = -1;
        char *newaddr = NULL;
        char *newbrd = NULL;
@@ -289,6 +314,12 @@ static int do_set(int argc, char **argv)
                                duparg("txqueuelen", *argv);
                        if (get_integer(&qlen,  *argv, 0))
                                invarg("Invalid \"txqueuelen\" value\n", *argv);
+               } else if (matches(*argv, "group") == 0) {
+                       NEXT_ARG();
+                       if (group != 0)
+                               duparg("group", *argv);
+                       if (get_integer(&group, *argv, 0) || group == 0)
+                               invarg("Invalid \"group\" value\n", *argv);
                } else if (strcmp(*argv, "mtu") == 0) {
                        NEXT_ARG();
                        if (mtu != -1)
@@ -406,6 +437,10 @@ static int do_set(int argc, char **argv)
                                return -1;
                }
        }
+       if (group) {
+               if (set_group(dev, group) < 0)
+                       return -1;
+       }
        if (mask)
                return do_chflags(dev, flags, mask);
        return 0;


-- 
Bazsi

-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to