From patchwork Fri Jun 29 03:23:14 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander 'lynxis' Couzens X-Patchwork-Id: 936573 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=lists.openwrt.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=fe80.eu Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="VPtcpq+x"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41H26s3JHjz9s01 for ; Fri, 29 Jun 2018 13:23:49 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:Subject:Message-Id: Date:To:From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References: List-Owner; bh=hm32dEQQg35vQhHDx+AU7Zw0DBpXLlucZkY19IEzVMs=; b=VPtcpq+xNjBS2Z o5dbEuwd86m1l/gvQ6EBQ2a6Y2exMYjR9I9V9OGdBpdWOHkfuzHohG8WuoIdMN8rBq2a2+wsCrv8E 9/ZFiMdiEFO2lVR3anQVGbFKD7P/tIRVkTjRWY9Ytaek5DfHFfVevMrn4oNSQVzbeT87dyc8iVFk/ DWvgTC1iYFDq1y5qqiNptBVwEaSWPCtAU3lztcReF7VUGDrtoAPLtWw6s6XqALgSPZlCwsLhx/9Po qgBkns8k7DI5XV00hs0Qpdq7JZlPSrsO0KjaCXqRgSBhEIaIzwsDojcXdvofCmRqhDGprZEgJWGGF 0BcXHXMR/+u8nou4d8OA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fYk0d-0007Y7-2U; Fri, 29 Jun 2018 03:23:43 +0000 Received: from mail.base45.de ([2001:67c:2050:320::77]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fYk0Y-0007Wy-DM for openwrt-devel@lists.openwrt.org; Fri, 29 Jun 2018 03:23:41 +0000 Received: from p200300f00bc58f003862bf6fe76ba789.dip0.t-ipconnect.de ([2003:f0:bc5:8f00:3862:bf6f:e76b:a789] helo=lazus.yip) by mail.base45.de with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.89) (envelope-from ) id 1fYk0H-0007Qt-SO; Fri, 29 Jun 2018 03:23:21 +0000 From: Alexander Couzens To: openwrt-devel@lists.openwrt.org Date: Fri, 29 Jun 2018 05:23:14 +0200 Message-Id: <20180629032315.7906-1-lynxis@fe80.eu> X-Mailer: git-send-email 2.18.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180628_202338_612222_AE92F729 X-CRM114-Status: UNSURE ( 6.81 ) X-CRM114-Notice: Please train this message. X-Spam-Score: -0.0 (/) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record Subject: [OpenWrt-Devel] [PATCH 1/2] Introduce new interface event "create" (IFEV_CREATE) X-BeenThere: openwrt-devel@lists.openwrt.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Hans Dedecker , Alexander Couzens MIME-Version: 1.0 Sender: "openwrt-devel" Errors-To: openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org "create" will be called before the proto handlers initialised. Acked-by: Hans Dedecker --- interface-event.c | 1 + interface.c | 1 + interface.h | 2 ++ 3 files changed, 4 insertions(+) diff --git a/interface-event.c b/interface-event.c index 86e8f5488da8..a40f6dc883d3 100644 --- a/interface-event.c +++ b/interface-event.c @@ -38,6 +38,7 @@ static const char * const eventnames[] = { [IFEV_FREE] = "free", [IFEV_RELOAD] = "reload", [IFEV_LINK_UP] = "iflink", + [IFEV_CREATE] = "create", }; static void diff --git a/interface.c b/interface.c index 2a23984922a1..400c605efc0c 100644 --- a/interface.c +++ b/interface.c @@ -1275,6 +1275,7 @@ interface_update(struct vlist_tree *tree, struct vlist_node *node_new, set_config_state(if_old, IFC_REMOVE); } else if (node_new) { D(INTERFACE, "Create interface '%s'\n", if_new->name); + interface_event(if_new, IFEV_CREATE); proto_init_interface(if_new, if_new->config); interface_claim_device(if_new); netifd_ubus_add_interface(if_new); diff --git a/interface.h b/interface.h index 0e58f69c26e0..e5639eb326cd 100644 --- a/interface.h +++ b/interface.h @@ -28,6 +28,8 @@ enum interface_event { IFEV_FREE, IFEV_RELOAD, IFEV_LINK_UP, + /* send when a new interface created. This is before proto handlers has been attached. */ + IFEV_CREATE, }; enum interface_state { From patchwork Fri Jun 29 03:23:15 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander 'lynxis' Couzens X-Patchwork-Id: 936574 X-Patchwork-Delegate: blogic@openwrt.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=lists.openwrt.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=fe80.eu Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="Rnlsq8V2"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41H27J5KN4z9s0w for ; Fri, 29 Jun 2018 13:24:12 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:Subject:References: In-Reply-To:Message-Id:Date:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=TIfEwxhtcKaDf+2JSsNOZUgCxRTfc5G4q0g6kZHxsUo=; b=Rnlsq8V2iUdi1z PzLJeTzLkpnUNT30YUJW5P1KytgmEYJLJaZ2Fl77Ein7H1dLKTczeTmDZCcMR3exdcc5SJMLeyCF1 5nI83Y9eqcgGoBwLQ2x98MEFYmxNHyFIr+EkVM+J/XFe5/USxILRDGsIPa4pIMai+Vrl91inA1oLN KALhF5uiunU60HQy56Lc+h1ZLoqsjvfssShiAQtcSZQFs1aNZqFfKSN3c5fqSIBY90P9limdX20ya c0UTAU2HdD0FM8ntFTkP1NsfGPgxAYb+uwnXUZEORq3sZvAY7T/zgmPNBXlK/rs/cVl+7p8wuhJdk NInvKYr/tGlZ4kINd+Iw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fYk0p-0007fq-4j; Fri, 29 Jun 2018 03:23:55 +0000 Received: from mail.base45.de ([2001:67c:2050:320::77]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fYk0Y-0007XI-DL for openwrt-devel@lists.openwrt.org; Fri, 29 Jun 2018 03:23:41 +0000 Received: from p200300f00bc58f003862bf6fe76ba789.dip0.t-ipconnect.de ([2003:f0:bc5:8f00:3862:bf6f:e76b:a789] helo=lazus.yip) by mail.base45.de with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.89) (envelope-from ) id 1fYk0T-0007Qt-Vu; Fri, 29 Jun 2018 03:23:34 +0000 From: Alexander Couzens To: openwrt-devel@lists.openwrt.org Date: Fri, 29 Jun 2018 05:23:15 +0200 Message-Id: <20180629032315.7906-2-lynxis@fe80.eu> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180629032315.7906-1-lynxis@fe80.eu> References: <20180629032315.7906-1-lynxis@fe80.eu> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180628_202338_612350_BBD3FBB8 X-CRM114-Status: GOOD ( 15.42 ) X-Spam-Score: -0.0 (/) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record Subject: [OpenWrt-Devel] [PATCH 2/2] iprule: rework interface based rules to handle dynamic interfaces X-BeenThere: openwrt-devel@lists.openwrt.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Hans Dedecker , Alexander Couzens MIME-Version: 1.0 Sender: "openwrt-devel" Errors-To: openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org Previous netifd would only apply `ip rule`s while config phase. If the iprule is depending on an interface (iif or oif), the rule will fail if the interface is not up. Allow iprules to track interfaces and their devices by using the interface events. Fixes: FS#1571 --- iprule.c | 179 ++++++++++++++++++++++++++++++++++++++++++++++++------- iprule.h | 9 +++ 2 files changed, 167 insertions(+), 21 deletions(-) diff --git a/iprule.c b/iprule.c index 7cf7422f4168..740965431b4c 100644 --- a/iprule.c +++ b/iprule.c @@ -2,6 +2,7 @@ * netifd - network interface daemon * Copyright (C) 2012 Felix Fietkau * Copyright (C) 2013 Jo-Philipp Wich + * Copyright (C) 2018 Alexander Couzens * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -12,6 +13,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +#include #include #include #include @@ -66,6 +68,16 @@ const struct uci_blob_param_list rule_attr_list = { .params = rule_attr, }; +/* interface based rules are dynamic. */ +static bool rule_ready(struct iprule *rule) { + if (rule->flags & IPRULE_OUT && rule->out_dev == NULL) + return false; + + if (rule->flags & IPRULE_IN && rule->in_dev == NULL) + return false; + + return true; +} static bool iprule_parse_mark(const char *mark, struct iprule *rule) @@ -97,13 +109,105 @@ iprule_parse_mark(const char *mark, struct iprule *rule) return true; } +/* called on interface changes of the incoming interface */ +static void rule_in_cb( + struct interface_user *dep, + struct interface *iface, + enum interface_event ev) +{ + struct iprule *rule = container_of(dep, struct iprule, in_iface_user); + + switch (ev) { + case IFEV_UP: + if (!iface->l3_dev.dev) + break; + memcpy(rule->in_dev, iface->l3_dev.dev->ifname, sizeof(rule->in_dev)); + if (rule_ready(rule)) + system_add_iprule(rule); + break; + case IFEV_DOWN: + case IFEV_UP_FAILED: + case IFEV_FREE: + if (rule_ready(rule)) + system_del_iprule(rule); + rule->in_dev[0] = 0; + break; + default: + break; + } +} + +/* called on interface changes of the outgoing interface */ +static void rule_out_cb( + struct interface_user *dep, + struct interface *iface, + enum interface_event ev) +{ + struct iprule *rule = container_of(dep, struct iprule, out_iface_user); + + switch (ev) { + case IFEV_UP: + if (!iface->l3_dev.dev) + break; + memcpy(rule->out_dev, iface->l3_dev.dev->ifname, sizeof(rule->out_dev)); + if (rule_ready(rule)) + system_add_iprule(rule); + break; + case IFEV_DOWN: + case IFEV_UP_FAILED: + case IFEV_FREE: + if (rule_ready(rule)) + system_del_iprule(rule); + rule->out_dev[0] = 0; + break; + default: + break; + } +} + +/* called on all interface events */ +static void generic_interface_cb( + struct interface_user *dep, + struct interface *iface, + enum interface_event ev) +{ + struct iprule *rule; + + if (ev != IFEV_CREATE) + return; + + /* add new interfaces to rules */ + vlist_for_each_element(&iprules, rule, node) { + if (rule_ready(rule)) + continue; + + if (!strcmp(rule->out_iface, iface->name)) { + assert(!rule->out_dev); + memcpy(rule->out_dev, iface->l3_dev.dev->ifname, sizeof(rule->out_dev)); + interface_add_user(&rule->out_iface_user, iface); + } + + if (!strcmp(rule->in_iface, iface->name)) { + assert(!rule->in_dev); + memcpy(rule->in_dev, iface->l3_dev.dev->ifname, sizeof(rule->in_dev)); + interface_add_user(&rule->in_iface_user, iface); + } + + if (rule_ready(rule)) + system_add_iprule(rule); + } +} + +struct interface_user generic_listener = { + .cb = generic_interface_cb +}; + void iprule_add(struct blob_attr *attr, bool v6) { - struct interface *iif = NULL, *oif = NULL; struct blob_attr *tb[__RULE_MAX], *cur; - struct interface *iface; struct iprule *rule; + char *iface_name; int af = v6 ? AF_INET6 : AF_INET; blobmsg_parse(rule_attr, __RULE_MAX, tb, blobmsg_data(attr), blobmsg_data_len(attr)); @@ -119,26 +223,16 @@ iprule_add(struct blob_attr *attr, bool v6) rule->invert = blobmsg_get_bool(cur); if ((cur = tb[RULE_INTERFACE_IN]) != NULL) { - iif = vlist_find(&interfaces, blobmsg_data(cur), iface, node); - - if (!iif || !iif->l3_dev.dev) { - DPRINTF("Failed to resolve device of network: %s\n", (char *) blobmsg_data(cur)); - goto error; - } - - memcpy(rule->in_dev, iif->l3_dev.dev->ifname, sizeof(rule->in_dev)); + iface_name = calloc(1, strlen(blobmsg_data(cur)) + 1); + rule->in_iface = strcpy(iface_name, blobmsg_data(cur)); + rule->in_iface_user.cb = &rule_in_cb; rule->flags |= IPRULE_IN; } if ((cur = tb[RULE_INTERFACE_OUT]) != NULL) { - oif = vlist_find(&interfaces, blobmsg_data(cur), iface, node); - - if (!oif || !oif->l3_dev.dev) { - DPRINTF("Failed to resolve device of network: %s\n", (char *) blobmsg_data(cur)); - goto error; - } - - memcpy(rule->out_dev, oif->l3_dev.dev->ifname, sizeof(rule->out_dev)); + iface_name = calloc(1, strlen(blobmsg_data(cur)) + 1); + rule->out_iface = strcpy(iface_name, blobmsg_data(cur)); + rule->out_iface_user.cb = &rule_out_cb; rule->flags |= IPRULE_OUT; } @@ -238,6 +332,31 @@ rule_cmp(const void *k1, const void *k2, void *ptr) return memcmp(k1, k2, sizeof(struct iprule)-offsetof(struct iprule, flags)); } +static void deregister_interfaces(struct iprule *rule) +{ + if (rule->flags & IPRULE_IN && rule->in_iface_user.iface) + interface_remove_user(&rule->in_iface_user); + + if (rule->flags & IPRULE_OUT && rule->out_iface_user.iface) + interface_remove_user(&rule->out_iface_user); +} + +static void register_interfaces(struct iprule *rule) +{ + struct interface *iface, *tmp; + + if (rule->flags & IPRULE_IN) { + tmp = vlist_find(&interfaces, rule->in_iface, iface, node); + if (tmp) + interface_add_user(&rule->in_iface_user, tmp); + } + if (rule->flags & IPRULE_OUT) { + tmp = vlist_find(&interfaces, rule->out_iface, iface, node); + if (tmp) + interface_add_user(&rule->out_iface_user, tmp); + } +} + static void iprule_update_rule(struct vlist_tree *tree, struct vlist_node *node_new, struct vlist_node *node_old) @@ -248,16 +367,34 @@ iprule_update_rule(struct vlist_tree *tree, rule_new = container_of(node_new, struct iprule, node); if (node_old) { - system_del_iprule(rule_old); + if (rule_ready(rule_old)) + system_del_iprule(rule_old); + + if (rule_old->flags & (IPRULE_IN | IPRULE_OUT)) + deregister_interfaces(rule_old); + + if (rule_old->in_iface) + free(rule_old->in_iface); + + if (rule_old->out_iface) + free(rule_old->out_iface); + free(rule_old); } - if (node_new) - system_add_iprule(rule_new); + if (node_new) { + /* interface based rules calls system_add_iprule over the event cb */ + if (rule_new->flags & (IPRULE_IN | IPRULE_OUT)) { + register_interfaces(rule_new); + } else { + system_add_iprule(rule_new); + } + } } static void __init iprule_init_list(void) { vlist_init(&iprules, rule_cmp, iprule_update_rule); + interface_add_user(&generic_listener, NULL); } diff --git a/iprule.h b/iprule.h index b723bdb05d7d..f05c3c93b4a1 100644 --- a/iprule.h +++ b/iprule.h @@ -74,6 +74,15 @@ struct iprule { bool invert; + /* uci interface name */ + char *in_iface; + char *out_iface; + + /* to receive interface events */ + struct interface_user in_iface_user; + struct interface_user out_iface_user; + + /* device name */ char in_dev[IFNAMSIZ + 1]; char out_dev[IFNAMSIZ + 1];