From patchwork Fri Dec 15 18:28:00 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tom Herbert X-Patchwork-Id: 849355 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=quantonium-net.20150623.gappssmtp.com header.i=@quantonium-net.20150623.gappssmtp.com header.b="DB52iKXm"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3yyzTS5gkTz9sBW for ; Sat, 16 Dec 2017 05:28:44 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756296AbdLOS2n (ORCPT ); Fri, 15 Dec 2017 13:28:43 -0500 Received: from mail-pf0-f196.google.com ([209.85.192.196]:42220 "EHLO mail-pf0-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756144AbdLOS2f (ORCPT ); Fri, 15 Dec 2017 13:28:35 -0500 Received: by mail-pf0-f196.google.com with SMTP id d23so6700764pfe.9 for ; Fri, 15 Dec 2017 10:28:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quantonium-net.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=PyzpvwDRZNgUYYf1sPwod8/m/PulMyCEUy8VGU8l6+o=; b=DB52iKXmurtPhLl3RUG0JYgQ96BxDn415O8PHwRpdJRQ+TEK1tKldAiuiWmWuNIZLV s+KtvPHu58yq+6KnX14ZzwCCQv7INlE8bgSO71hFDI1xScvHl4vTNWe1mqebUVWtGsw5 s3wtfdVgbF/aAKv0ikAQtioMnIrjJxF+WmIoaMm8Jem52n3fXoXAlsXkOvKZKiZ58n7Z Fx/CRMV93M7nyzabCZVNNBuDUdpus/Kt153FNq+tKUlNrJgOZmWAA1y8m6XvXfrAAPuE UjPFYArBWyKgJRGm7qFmgBpTDKSrWLNdVwaDE4plMghJ8XaeSXAYZViWeRGNPGf2ybEw kSaQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=PyzpvwDRZNgUYYf1sPwod8/m/PulMyCEUy8VGU8l6+o=; b=mhGqGujYkUf9L0k/2H12zNG6aw4Fp2WNU/MPTHCBiwG1kqcj3WEBTUUAbOelI4RqVq d2Mvc3GLcXx3RK2q3A0xtLB7lEf68++/39ABHUdzAS5BdxmLJu2/KK9luygt+10jzYxw zpH7MNnX1l3J9V6LUWaAXtjqxKQX6hfIObd5NWPo1DHCSHsDyIfdq2BqHE4faOw/IRLZ u3s3zxIZChMrLDfzhn9rYIAUJEMWCvwx6VDgVnU8k2dgRgsTdOB4BYsEkKiTj9FhvA0m gvSve1WAmOrS07xywZSgkmZAg1XVfkLE50lENJHpT/2Ok6wq42EPdkiRmCKUM0XrUiZA CPUg== X-Gm-Message-State: AKGB3mIMNG3JX6T5cccBwTqKumXOtU0giH2rM1/GVzYQnpKkpKbuBmRi Qe144OGOhvVKXCB3EUvlV7pWwg== X-Google-Smtp-Source: ACJfBov5wwh352oVxBf1MciY4nzoih28GcgZ9vnPFhFmT1ppJqqUZGa6z+oHPAAi3uLL3vJ+1gmVmA== X-Received: by 10.98.7.27 with SMTP id b27mr14264245pfd.240.1513362514229; Fri, 15 Dec 2017 10:28:34 -0800 (PST) Received: from localhost.localdomain (67-207-98-108.static.wiline.com. [67.207.98.108]) by smtp.gmail.com with ESMTPSA id 69sm14120903pfj.28.2017.12.15.10.28.32 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 15 Dec 2017 10:28:33 -0800 (PST) From: Tom Herbert To: davem@davemloft.net Cc: netdev@vger.kernel.org, roopa@cumulusnetworks.com, rohit@quantonium.net, Tom Herbert Subject: [PATCH v4 net-next 6/6] ila: Route notify Date: Fri, 15 Dec 2017 10:28:00 -0800 Message-Id: <20171215182800.10248-7-tom@quantonium.net> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20171215182800.10248-1-tom@quantonium.net> References: <20171215182800.10248-1-tom@quantonium.net> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Implement RTM notifications for ILA routers. This adds support to ILA LWT to send a netlink RTM message when a router is uses. THe ILA notify mechanism can be used in two contexts: - On an ILA forwarding cache a route prefix can be configured to do an ILA notification. This method is used when address resolution needs to be done on an address. - One an ILA router an ILA host route entry may include a noitification. The purpose of this is to get a notification to a userspace daemon to send and ILA redirect Signed-off-by: Tom Herbert --- include/uapi/linux/ila.h | 2 + include/uapi/linux/rtnetlink.h | 8 +- net/ipv6/ila/ila_lwt.c | 268 ++++++++++++++++++++++++++++------------- 3 files changed, 193 insertions(+), 85 deletions(-) diff --git a/include/uapi/linux/ila.h b/include/uapi/linux/ila.h index db45d3e49a12..5675f3e71fac 100644 --- a/include/uapi/linux/ila.h +++ b/include/uapi/linux/ila.h @@ -19,6 +19,8 @@ enum { ILA_ATTR_CSUM_MODE, /* u8 */ ILA_ATTR_IDENT_TYPE, /* u8 */ ILA_ATTR_HOOK_TYPE, /* u8 */ + ILA_ATTR_NOTIFY_DST, /* flag */ + ILA_ATTR_NOTIFY_SRC, /* flag */ __ILA_ATTR_MAX, }; diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h index d8b5f80c2ea6..8d358a300d8a 100644 --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h @@ -13,7 +13,8 @@ */ #define RTNL_FAMILY_IPMR 128 #define RTNL_FAMILY_IP6MR 129 -#define RTNL_FAMILY_MAX 129 +#define RTNL_FAMILY_ILA 130 +#define RTNL_FAMILY_MAX 130 /**** * Routing/neighbour discovery messages. @@ -150,6 +151,9 @@ enum { RTM_NEWCACHEREPORT = 96, #define RTM_NEWCACHEREPORT RTM_NEWCACHEREPORT + RTM_ADDR_RESOLVE = 98, +#define RTM_ADDR_RESOLVE RTM_ADDR_RESOLVE + __RTM_MAX, #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) }; @@ -676,6 +680,8 @@ enum rtnetlink_groups { #define RTNLGRP_IPV4_MROUTE_R RTNLGRP_IPV4_MROUTE_R RTNLGRP_IPV6_MROUTE_R, #define RTNLGRP_IPV6_MROUTE_R RTNLGRP_IPV6_MROUTE_R + RTNLGRP_ILA_NOTIFY, +#define RTNLGRP_ILA_NOTIFY RTNLGRP_ILA_NOTIFY __RTNLGRP_MAX }; #define RTNLGRP_MAX (__RTNLGRP_MAX - 1) diff --git a/net/ipv6/ila/ila_lwt.c b/net/ipv6/ila/ila_lwt.c index 9f1e46a1468e..303c91e3bf76 100644 --- a/net/ipv6/ila/ila_lwt.c +++ b/net/ipv6/ila/ila_lwt.c @@ -19,10 +19,15 @@ struct ila_lwt { struct ila_params p; struct dst_cache dst_cache; + u8 hook_type; u32 connected : 1; - u32 lwt_output : 1; + u32 xlat : 1; + u32 notify : 2; }; +#define ILA_NOTIFY_DST 1 +#define ILA_NOTIFY_SRC 2 + static inline struct ila_lwt *ila_lwt_lwtunnel( struct lwtunnel_state *lwt) { @@ -35,6 +40,67 @@ static inline struct ila_params *ila_params_lwtunnel( return &ila_lwt_lwtunnel(lwt)->p; } +static size_t ila_rslv_msgsize(void) +{ + size_t len = + NLMSG_ALIGN(sizeof(struct rtmsg)) + + nla_total_size(16) /* RTA_DST */ + + nla_total_size(16) /* RTA_SRC */ + ; + + return len; +} + +void ila_notify(struct net *net, struct sk_buff *skb, struct ila_lwt *lwt) +{ + struct ipv6hdr *ip6h = ipv6_hdr(skb); + int flags = NLM_F_MULTI; + struct sk_buff *nlskb; + struct nlmsghdr *nlh; + struct rtmsg *rtm; + int err = 0; + + /* Send ILA notification to user */ + nlskb = nlmsg_new(ila_rslv_msgsize(), GFP_KERNEL); + if (!nlskb) + return; + + nlh = nlmsg_put(nlskb, 0, 0, RTM_ADDR_RESOLVE, sizeof(*rtm), flags); + if (!nlh) { + err = -EMSGSIZE; + goto errout; + } + + rtm = nlmsg_data(nlh); + rtm->rtm_family = AF_INET6; + rtm->rtm_dst_len = 128; + rtm->rtm_src_len = 0; + rtm->rtm_tos = 0; + rtm->rtm_table = RT6_TABLE_UNSPEC; + rtm->rtm_type = RTN_UNICAST; + rtm->rtm_scope = RT_SCOPE_UNIVERSE; + + if (((lwt->notify & ILA_NOTIFY_DST) && + nla_put_in6_addr(nlskb, RTA_DST, &ip6h->daddr)) || + ((lwt->notify & ILA_NOTIFY_SRC) && + nla_put_in6_addr(nlskb, RTA_SRC, &ip6h->saddr))) { + nlmsg_cancel(nlskb, nlh); + err = -EMSGSIZE; + goto errout; + } + + nlmsg_end(nlskb, nlh); + + rtnl_notify(nlskb, net, 0, RTNLGRP_ILA_NOTIFY, NULL, GFP_ATOMIC); + + return; + +errout: + kfree_skb(nlskb); + WARN_ON(err == -EMSGSIZE); + rtnl_set_sk_err(net, RTNLGRP_ILA_NOTIFY, err); +} + static int ila_output(struct net *net, struct sock *sk, struct sk_buff *skb) { struct dst_entry *orig_dst = skb_dst(skb); @@ -46,11 +112,14 @@ static int ila_output(struct net *net, struct sock *sk, struct sk_buff *skb) if (skb->protocol != htons(ETH_P_IPV6)) goto drop; - if (ilwt->lwt_output) + if (ilwt->xlat) ila_update_ipv6_locator(skb, ila_params_lwtunnel(orig_dst->lwtstate), true); + if (ilwt->notify) + ila_notify(net, skb, ilwt); + if (rt->rt6i_flags & (RTF_GATEWAY | RTF_CACHE)) { /* Already have a next hop address in route, no need for * dest cache route. @@ -106,11 +175,14 @@ static int ila_input(struct sk_buff *skb) if (skb->protocol != htons(ETH_P_IPV6)) goto drop; - if (!ilwt->lwt_output) + if (ilwt->xlat) ila_update_ipv6_locator(skb, ila_params_lwtunnel(dst->lwtstate), false); + if (ilwt->notify) + ila_notify(dev_net(dst->dev), skb, ilwt); + return dst->lwtstate->orig_input(skb); drop: @@ -123,6 +195,8 @@ static const struct nla_policy ila_nl_policy[ILA_ATTR_MAX + 1] = { [ILA_ATTR_CSUM_MODE] = { .type = NLA_U8, }, [ILA_ATTR_IDENT_TYPE] = { .type = NLA_U8, }, [ILA_ATTR_HOOK_TYPE] = { .type = NLA_U8, }, + [ILA_ATTR_NOTIFY_DST] = { .type = NLA_FLAG }, + [ILA_ATTR_NOTIFY_SRC] = { .type = NLA_FLAG }, }; static int ila_build_state(struct net *net, struct nlattr *nla, @@ -130,64 +204,73 @@ static int ila_build_state(struct net *net, struct nlattr *nla, struct lwtunnel_state **ts, struct netlink_ext_ack *extack) { - struct ila_lwt *ilwt; - struct ila_params *p; - struct nlattr *tb[ILA_ATTR_MAX + 1]; - struct lwtunnel_state *newts; const struct fib6_config *cfg6 = cfg; - struct ila_addr *iaddr; + struct ila_addr *iaddr = (struct ila_addr *)&cfg6->fc_dst; u8 ident_type = ILA_ATYPE_USE_FORMAT; u8 hook_type = ILA_HOOK_ROUTE_OUTPUT; + struct nlattr *tb[ILA_ATTR_MAX + 1]; u8 csum_mode = ILA_CSUM_NO_ACTION; - bool lwt_output = true; + struct lwtunnel_state *newts; + struct ila_lwt *ilwt; + struct ila_params *p; u8 eff_ident_type; - int ret; + int err; if (family != AF_INET6) return -EINVAL; - ret = nla_parse_nested(tb, ILA_ATTR_MAX, nla, ila_nl_policy, extack); - if (ret < 0) - return ret; + err = nla_parse_nested(tb, ILA_ATTR_MAX, nla, ila_nl_policy, extack); + if (err < 0) + return err; - if (!tb[ILA_ATTR_LOCATOR]) - return -EINVAL; + if (tb[ILA_ATTR_LOCATOR]) { + /* Doing ILA translation */ - iaddr = (struct ila_addr *)&cfg6->fc_dst; + if (tb[ILA_ATTR_IDENT_TYPE]) + ident_type = nla_get_u8(tb[ILA_ATTR_IDENT_TYPE]); - if (tb[ILA_ATTR_IDENT_TYPE]) - ident_type = nla_get_u8(tb[ILA_ATTR_IDENT_TYPE]); + if (ident_type == ILA_ATYPE_USE_FORMAT) { + /* Infer identifier type from type field in formatted + * identifier. + */ - if (ident_type == ILA_ATYPE_USE_FORMAT) { - /* Infer identifier type from type field in formatted - * identifier. - */ + if (cfg6->fc_dst_len < 8 * + sizeof(struct ila_locator) + 3) { + /* Need to have full locator and at least type + * field included in destination + */ + return -EINVAL; + } + + eff_ident_type = iaddr->ident.type; + } else { + eff_ident_type = ident_type; + } - if (cfg6->fc_dst_len < 8 * sizeof(struct ila_locator) + 3) { - /* Need to have full locator and at least type field - * included in destination - */ + switch (eff_ident_type) { + case ILA_ATYPE_IID: + /* Don't allow ILA for IID type */ + return -EINVAL; + case ILA_ATYPE_LUID: + break; + case ILA_ATYPE_VIRT_V4: + case ILA_ATYPE_VIRT_UNI_V6: + case ILA_ATYPE_VIRT_MULTI_V6: + case ILA_ATYPE_NONLOCAL_ADDR: + /* These ILA formats are not supported yet. */ + default: return -EINVAL; } - eff_ident_type = iaddr->ident.type; - } else { - eff_ident_type = ident_type; - } + csum_mode = nla_get_u8(tb[ILA_ATTR_CSUM_MODE]); - switch (eff_ident_type) { - case ILA_ATYPE_IID: - /* Don't allow ILA for IID type */ - return -EINVAL; - case ILA_ATYPE_LUID: - break; - case ILA_ATYPE_VIRT_V4: - case ILA_ATYPE_VIRT_UNI_V6: - case ILA_ATYPE_VIRT_MULTI_V6: - case ILA_ATYPE_NONLOCAL_ADDR: - /* These ILA formats are not supported yet. */ - default: - return -EINVAL; + if (csum_mode == ILA_CSUM_NEUTRAL_MAP && + ila_csum_neutral_set(iaddr->ident)) { + /* Don't allow translation if checksum neutral bit is + * configured and it's set in the SIR address. + */ + return -EINVAL; + } } if (tb[ILA_ATTR_HOOK_TYPE]) @@ -195,58 +278,62 @@ static int ila_build_state(struct net *net, struct nlattr *nla, switch (hook_type) { case ILA_HOOK_ROUTE_OUTPUT: - lwt_output = true; - break; case ILA_HOOK_ROUTE_INPUT: - lwt_output = false; break; default: return -EINVAL; } - if (tb[ILA_ATTR_CSUM_MODE]) - csum_mode = nla_get_u8(tb[ILA_ATTR_CSUM_MODE]); - - if (csum_mode == ILA_CSUM_NEUTRAL_MAP && - ila_csum_neutral_set(iaddr->ident)) { - /* Don't allow translation if checksum neutral bit is - * configured and it's set in the SIR address. - */ - return -EINVAL; - } - newts = lwtunnel_state_alloc(sizeof(*ilwt)); if (!newts) return -ENOMEM; ilwt = ila_lwt_lwtunnel(newts); - ret = dst_cache_init(&ilwt->dst_cache, GFP_ATOMIC); - if (ret) { + + err = dst_cache_init(&ilwt->dst_cache, GFP_ATOMIC); + if (err) { kfree(newts); - return ret; + return err; } - ilwt->lwt_output = !!lwt_output; + newts->type = LWTUNNEL_ENCAP_ILA; - p = ila_params_lwtunnel(newts); + switch (hook_type) { + case ILA_HOOK_ROUTE_OUTPUT: + newts->flags |= LWTUNNEL_STATE_OUTPUT_REDIRECT; + break; + case ILA_HOOK_ROUTE_INPUT: + newts->flags |= LWTUNNEL_STATE_INPUT_REDIRECT; + break; + } - p->csum_mode = csum_mode; - p->ident_type = ident_type; - p->locator.v64 = (__force __be64)nla_get_u64(tb[ILA_ATTR_LOCATOR]); + ilwt->hook_type = hook_type; - /* Precompute checksum difference for translation since we - * know both the old locator and the new one. - */ - p->locator_match = iaddr->loc; + if (tb[ILA_ATTR_NOTIFY_DST]) + ilwt->notify |= ILA_NOTIFY_DST; - ila_init_saved_csum(p); + if (tb[ILA_ATTR_NOTIFY_SRC]) + ilwt->notify |= ILA_NOTIFY_SRC; - newts->type = LWTUNNEL_ENCAP_ILA; - newts->flags |= LWTUNNEL_STATE_OUTPUT_REDIRECT | - LWTUNNEL_STATE_INPUT_REDIRECT; + p = ila_params_lwtunnel(newts); - if (cfg6->fc_dst_len == 8 * sizeof(struct in6_addr)) - ilwt->connected = 1; + if (tb[ILA_ATTR_LOCATOR]) { + ilwt->xlat = true; + p->csum_mode = csum_mode; + p->ident_type = ident_type; + p->locator.v64 = (__force __be64)nla_get_u64( + tb[ILA_ATTR_LOCATOR]); + + /* Precompute checksum difference for translation since we + * know both the old locator and the new one. + */ + p->locator_match = iaddr->loc; + + ila_init_saved_csum(p); + + if (cfg6->fc_dst_len == 8 * sizeof(struct in6_addr)) + ilwt->connected = 1; + } *ts = newts; @@ -264,21 +351,32 @@ static int ila_fill_encap_info(struct sk_buff *skb, struct ila_params *p = ila_params_lwtunnel(lwtstate); struct ila_lwt *ilwt = ila_lwt_lwtunnel(lwtstate); - if (nla_put_u64_64bit(skb, ILA_ATTR_LOCATOR, (__force u64)p->locator.v64, - ILA_ATTR_PAD)) + if (ilwt->xlat) { + if (nla_put_u64_64bit(skb, ILA_ATTR_LOCATOR, + (__force u64)p->locator.v64, + ILA_ATTR_PAD)) goto nla_put_failure; - if (nla_put_u8(skb, ILA_ATTR_CSUM_MODE, (__force u8)p->csum_mode)) - goto nla_put_failure; + if (nla_put_u8(skb, ILA_ATTR_CSUM_MODE, + (__force u8)p->csum_mode)) + goto nla_put_failure; - if (nla_put_u8(skb, ILA_ATTR_IDENT_TYPE, (__force u8)p->ident_type)) - goto nla_put_failure; + if (nla_put_u8(skb, ILA_ATTR_IDENT_TYPE, + (__force u8)p->ident_type)) + goto nla_put_failure; + } - if (nla_put_u8(skb, ILA_ATTR_HOOK_TYPE, - ilwt->lwt_output ? ILA_HOOK_ROUTE_OUTPUT : - ILA_HOOK_ROUTE_INPUT)) + if (nla_put_u8(skb, ILA_ATTR_HOOK_TYPE, ilwt->hook_type)) goto nla_put_failure; + if (ilwt->notify & ILA_NOTIFY_DST) + if (nla_put_flag(skb, ILA_ATTR_NOTIFY_DST)) + goto nla_put_failure; + + if (ilwt->notify & ILA_NOTIFY_SRC) + if (nla_put_flag(skb, ILA_ATTR_NOTIFY_SRC)) + goto nla_put_failure; + return 0; nla_put_failure: @@ -291,6 +389,8 @@ static int ila_encap_nlsize(struct lwtunnel_state *lwtstate) nla_total_size(sizeof(u8)) + /* ILA_ATTR_CSUM_MODE */ nla_total_size(sizeof(u8)) + /* ILA_ATTR_IDENT_TYPE */ nla_total_size(sizeof(u8)) + /* ILA_ATTR_HOOK_TYPE */ + nla_total_size(0) + /* ILA_ATTR_NOTIFY_DST */ + nla_total_size(0) + /* ILA_ATTR_NOTIFY_SRC */ 0; }