diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 93d378aa95f8..733f3c5d853d 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -344,6 +344,7 @@ ./services/networking/tlsdated.nix ./services/networking/tox-bootstrapd.nix ./services/networking/tvheadend.nix + ./services/networking/ubuntu-fan.nix ./services/networking/unbound.nix ./services/networking/unifi.nix ./services/networking/vsftpd.nix diff --git a/nixos/modules/services/networking/ubuntu-fan.nix b/nixos/modules/services/networking/ubuntu-fan.nix new file mode 100644 index 000000000000..2759a671b81f --- /dev/null +++ b/nixos/modules/services/networking/ubuntu-fan.nix @@ -0,0 +1,60 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.networking.ubuntu-fan; + modprobe = "${config.system.sbin.modprobe}/sbin/modprobe"; + +in + +{ + + ###### interface + + options = { + + networking.ubuntu-fan = { + + enable = mkEnableOption "Ubuntu FAN Networking"; + + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + environment.systemPackages = [ pkgs.fanctl ]; + + systemd.services.ubuntu-fan = { + description = "Ubuntu FAN Networking"; + wantedBy = [ "multi-user.target" ]; + after = [ "network-online.target" ]; + before = [ "docker.service" ]; + restartIfChanged = false; + preStart = '' + if [ ! -f /proc/sys/net/fan/version ]; then + ${modprobe} ipip + if [ ! -f /proc/sys/net/fan/version ]; then + echo "The Ubuntu Fan Networking patches have not been applied to this kernel!" 1>&2 + exit 1 + fi + fi + + mkdir -p /var/lib/ubuntu-fan + ''; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = "${pkgs.fanctl}/bin/fanctl up -a"; + ExecStop = "${pkgs.fanctl}/bin/fanctl down -a"; + }; + }; + + }; + +} diff --git a/pkgs/os-specific/linux/fanctl/default.nix b/pkgs/os-specific/linux/fanctl/default.nix new file mode 100644 index 000000000000..f0b863e01488 --- /dev/null +++ b/pkgs/os-specific/linux/fanctl/default.nix @@ -0,0 +1,47 @@ +{ stdenv, lib, fetchbzr, makeWrapper, bridge-utils, iproute, dnsmasq, iptables, kmod, utillinux }: + +stdenv.mkDerivation rec { + name = "fanctl-${version}"; + + version = "0.3.0"; + + src = fetchbzr { + url = "https://code.launchpad.net/~ubuntu-branches/ubuntu/vivid/ubuntu-fan/vivid-updates"; + rev = 2; + sha256 = "1vcr2rg99g7sx1zynhiggjzc9y9z591i4535hbm21dysy3cisp7i"; + }; + + buildInputs = [ makeWrapper ]; + + # When given --conf-file="", dnsmasq still attempts to read /etc/dnsmasq.conf; + # if that files does not exist, dnsmasq subsequently fails, + # so we'll use /dev/null. + # + # Also, make sure /var/lib/ubuntu-fan exists before starting dnsmasq. + buildPhase = '' + substituteInPlace fanctl \ + --replace '--conf-file= ' \ + '--conf-file=/dev/null ' \ + --replace '/var/lib/misc' \ + '/var/lib/ubuntu-fan' + + sed -i '/dnsmasq -u/i \ + mkdir -p /var/lib/ubuntu-fan' fanctl + ''; + + installPhase = '' + mkdir -p $out/bin $out/man/man8 + cp fanctl.8 $out/man/man8 + cp fanctl $out/bin + wrapProgram $out/bin/fanctl --prefix PATH : \ + ${lib.makeSearchPath "bin" [ bridge-utils iproute dnsmasq iptables kmod utillinux ]}; + ''; + + meta = with lib; { + description = "Ubuntu FAN network support enablement"; + homepage = "https://launchpad.net/ubuntu/+source/ubuntu-fan"; + license = licenses.gpl2; + platforms = platforms.linux; + maintainers = with maintainers; [ cstrahan ]; + }; +} diff --git a/pkgs/os-specific/linux/iproute/default.nix b/pkgs/os-specific/linux/iproute/default.nix index 6fea4ba05e0d..6f5ec27c638e 100644 --- a/pkgs/os-specific/linux/iproute/default.nix +++ b/pkgs/os-specific/linux/iproute/default.nix @@ -1,4 +1,6 @@ -{ fetchurl, stdenv, flex, bison, db, iptables, pkgconfig }: +{ fetchurl, stdenv, lib, flex, bison, db, iptables, pkgconfig +, enableFan ? false +}: stdenv.mkDerivation rec { name = "iproute2-4.1.1"; @@ -8,6 +10,8 @@ stdenv.mkDerivation rec { sha256 = "0vz6m2k6hdrjlg4x0r3cd75lg9ysmndbsp35pm8494zvksc7l1vk"; }; + patches = lib.optionals enableFan [ ./ubuntu-fan.patch ]; + preConfigure = '' patchShebangs ./configure sed -e '/ARPDDIR/d' -i Makefile diff --git a/pkgs/os-specific/linux/iproute/ubuntu-fan.patch b/pkgs/os-specific/linux/iproute/ubuntu-fan.patch new file mode 100644 index 000000000000..e55425c2ce6a --- /dev/null +++ b/pkgs/os-specific/linux/iproute/ubuntu-fan.patch @@ -0,0 +1,164 @@ +This provides support for Ubuntu's Fan Networking [1]. + +These patches were pulled from: +https://code.launchpad.net/~ubuntu-branches/ubuntu/vivid/iproute2/vivid-proposed + +See revisions 18 and 19. + +[1] https://wiki.ubuntu.com/FanNetworking + +diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h +index 102ce7a..7b8f0e5 100644 +--- a/include/linux/if_tunnel.h ++++ b/include/linux/if_tunnel.h +@@ -57,6 +57,9 @@ enum { + IFLA_IPTUN_ENCAP_FLAGS, + IFLA_IPTUN_ENCAP_SPORT, + IFLA_IPTUN_ENCAP_DPORT, ++ ++ IFLA_IPTUN_FAN_UNDERLAY = 32, ++ IFLA_IPTUN_FAN_MAP = 33, + __IFLA_IPTUN_MAX, + }; + #define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1) +@@ -131,4 +134,20 @@ enum { + }; + + #define IFLA_VTI_MAX (__IFLA_VTI_MAX - 1) ++ ++enum { ++ IFLA_FAN_UNSPEC, ++ IFLA_FAN_MAPPING, ++ __IFLA_FAN_MAX, ++}; ++ ++#define IFLA_FAN_MAX (__IFLA_FAN_MAX - 1) ++ ++struct ip_tunnel_fan_map { ++ __be32 underlay; ++ __be32 overlay; ++ __u16 underlay_prefix; ++ __u16 overlay_prefix; ++}; ++ + #endif /* _IF_TUNNEL_H_ */ +diff --git a/ip/link_iptnl.c b/ip/link_iptnl.c +index 9d6bc98..ec3f05d 100644 +--- a/ip/link_iptnl.c ++++ b/ip/link_iptnl.c +@@ -49,6 +49,42 @@ static void usage(int sit) + print_usage(stderr, sit); + exit(-1); + } ++static int fan_parse_map(int *argcp, char ***argvp, struct nlmsghdr *n) ++{ ++ inet_prefix underlay, overlay; ++ struct ip_tunnel_fan_map map; ++ struct rtattr *nest; ++ char **argv = *argvp; ++ int argc = *argcp; ++ ++ nest = addattr_nest(n, 1024, IFLA_IPTUN_FAN_MAP); ++ while (argc > 0) { ++ char *colon = strchr(*argv, ':'); ++ ++ if (!colon) ++ break; ++ *colon = '\0'; ++ ++ if (get_prefix(&overlay, *argv, AF_INET)) ++ invarg("invalid fan-map overlay", *argv); ++ if (get_prefix(&underlay, colon + 1, AF_INET)) ++ invarg("invalid fan-map underlay", colon + 1); ++ ++ memcpy(&map.underlay, underlay.data, 4); ++ map.underlay_prefix = underlay.bitlen; ++ memcpy(&map.overlay, overlay.data, 4); ++ map.overlay_prefix = overlay.bitlen; ++ ++ argc--, argv++; ++ ++ addattr_l(n, 1024, IFLA_FAN_MAPPING, &map, sizeof(map)); ++ } ++ addattr_nest_end(n, nest); ++ ++ *argcp = argc; ++ *argvp = argv; ++ return 0; ++} + + static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv, + struct nlmsghdr *n) +@@ -66,6 +102,7 @@ static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv, + __u32 link = 0; + __u32 laddr = 0; + __u32 raddr = 0; ++ __u32 underlay = 0; + __u8 ttl = 0; + __u8 tos = 0; + __u8 pmtudisc = 1; +@@ -174,6 +211,13 @@ get_failed: + raddr = get_addr32(*argv); + else + raddr = 0; ++ } else if (strcmp(*argv, "underlay") == 0) { ++ NEXT_ARG(); ++ underlay = get_addr32(*argv); ++ } else if (strcmp(*argv, "fan-map") == 0) { ++ NEXT_ARG(); ++ if (fan_parse_map(&argc, &argv, n)) ++ invarg("invalid fan-map", *argv); + } else if (strcmp(*argv, "local") == 0) { + NEXT_ARG(); + if (strcmp(*argv, "any")) +@@ -318,9 +362,32 @@ get_failed: + } + } + ++ if (underlay) ++ addattr32(n, 1024, IFLA_IPTUN_FAN_UNDERLAY, underlay); ++ + return 0; + } + ++static void fan_print_map(FILE *f, struct rtattr *attr) ++{ ++ char b1[INET_ADDRSTRLEN], b2[INET_ADDRSTRLEN]; ++ struct ip_tunnel_fan_map *m; ++ struct rtattr *i; ++ int rem; ++ ++ fprintf(f, "fan-map "); ++ ++ rem = RTA_PAYLOAD(attr); ++ for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { ++ m = RTA_DATA(i); ++ fprintf(f, "%s/%d:%s/%d ", ++ rt_addr_n2a(AF_INET, sizeof(m->overlay), &m->overlay, b1, INET_ADDRSTRLEN), ++ m->overlay_prefix, ++ rt_addr_n2a(AF_INET, sizeof(m->overlay), &m->underlay, b2, INET_ADDRSTRLEN), ++ m->underlay_prefix); ++ } ++} ++ + static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) + { + char s1[1024]; +@@ -349,6 +416,17 @@ static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[ + + fprintf(f, "local %s ", local); + ++ if (tb[IFLA_IPTUN_FAN_UNDERLAY]) { ++ unsigned addr = rta_getattr_u32(tb[IFLA_IPTUN_FAN_UNDERLAY]); ++ ++ if (addr) ++ fprintf(f, "underlay %s ", ++ format_host(AF_INET, 4, &addr, s1, sizeof(s1))); ++ } ++ ++ if (tb[IFLA_IPTUN_FAN_MAP]) ++ fan_print_map(f, tb[IFLA_IPTUN_FAN_MAP]); ++ + if (tb[IFLA_IPTUN_LINK] && rta_getattr_u32(tb[IFLA_IPTUN_LINK])) { + unsigned link = rta_getattr_u32(tb[IFLA_IPTUN_LINK]); + const char *n = if_indextoname(link, s2); diff --git a/pkgs/os-specific/linux/kernel/patches.nix b/pkgs/os-specific/linux/kernel/patches.nix index 4ae1a4e41896..79d58a539f08 100644 --- a/pkgs/os-specific/linux/kernel/patches.nix +++ b/pkgs/os-specific/linux/kernel/patches.nix @@ -58,6 +58,16 @@ rec { patch = ./mips-ext3-n32.patch; }; + ubuntu_fan = + { name = "ubuntu-fan"; + patch = ./ubuntu-fan-3.patch; + }; + + ubuntu_fan_4 = + { name = "ubuntu-fan"; + patch = ./ubuntu-fan-4.patch; + }; + tuxonice_3_10 = makeTuxonicePatch { version = "2013-11-07"; kernelVersion = "3.10.18"; diff --git a/pkgs/os-specific/linux/kernel/ubuntu-fan-3.patch b/pkgs/os-specific/linux/kernel/ubuntu-fan-3.patch new file mode 100644 index 000000000000..c80950d06147 --- /dev/null +++ b/pkgs/os-specific/linux/kernel/ubuntu-fan-3.patch @@ -0,0 +1,616 @@ +From f3c956096902669c3529cb01d40deb0c759ed94f Mon Sep 17 00:00:00 2001 +From: Jay Vosburgh +Date: Wed, 1 Apr 2015 16:11:09 -0700 +Subject: [PATCH] UBUNTU: SAUCE: fan: Proof of concept implementation (v2) + +Modification to ipip tunnel driver to accept a new netlink option, +IFLA_IPTUN_FAN_UNDERLAY, which provides a /16 network prefix and enables +TX side destination address remapping for traffic entering the tunnel +(to be encapsulated). + +For an overlay (inner) address Y.A.B.C, the transformation is F.G.A.B, +where "F" and "G" are the first two octets of the underlay network (the +network portion of a /16), "A" and "B" are the low order two octets of the +underlay network host (the host portion of a /16), and "Y" is a configured +first octet of the overlay network. + +E.g., underlay host 10.88.3.4 with an overlay of 99 would host overlay +subnet 99.3.4.0/24. An overlay network datagram from 99.3.4.5 to 99.6.7.8 +would be directed to underlay host 10.88.6.7, which hosts overlay network +99.6.7.0/24. + +Includes net.fan.version sysctl as a sentinel for availability of the +fan functionality. + +NOTE: this requires an updated iproute2 to facilitate configuration of +the fan. + +BugLink: http://bugs.launchpad.net/bugs/1439706 +Signed-off-by: Jay Vosburgh +[apw@canonical.com: move IFLA_IPTUN_FAN_UNDERLAY up to avoid clashing + with future feature additions.] +Signed-off-by: Andy Whitcroft +--- + include/net/ip_tunnels.h | 6 +++ + include/uapi/linux/if_tunnel.h | 4 ++ + net/ipv4/ipip.c | 112 +++++++++++++++++++++++++++++++++++++++-- + 3 files changed, 117 insertions(+), 5 deletions(-) + +diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h +index 25a59eb..d7eada2 100644 +--- a/include/net/ip_tunnels.h ++++ b/include/net/ip_tunnels.h +@@ -51,6 +51,11 @@ struct ip_tunnel_dst { + __be32 saddr; + }; + ++/* Underlay address prefix for ipip fan mode */ ++struct ip_tunnel_fan { ++ u32 underlay; ++}; ++ + struct ip_tunnel { + struct ip_tunnel __rcu *next; + struct hlist_node hash_node; +@@ -82,6 +87,7 @@ struct ip_tunnel { + #endif + struct ip_tunnel_prl_entry __rcu *prl; /* potential router list */ + unsigned int prl_count; /* # of entries in PRL */ ++ struct ip_tunnel_fan fan; + int ip_tnl_net_id; + struct gro_cells gro_cells; + }; +diff --git a/include/uapi/linux/if_tunnel.h b/include/uapi/linux/if_tunnel.h +index bd3cc11..8f7d269 100644 +--- a/include/uapi/linux/if_tunnel.h ++++ b/include/uapi/linux/if_tunnel.h +@@ -57,6 +57,10 @@ enum { + IFLA_IPTUN_ENCAP_FLAGS, + IFLA_IPTUN_ENCAP_SPORT, + IFLA_IPTUN_ENCAP_DPORT, ++ ++ __IFLA_IPTUN_VENDOR_BREAK, /* Ensure new entries do not hit the below. */ ++ IFLA_IPTUN_FAN_UNDERLAY=32, ++ + __IFLA_IPTUN_MAX, + }; + #define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1) +diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c +index 40403114..e3c27cd 100644 +--- a/net/ipv4/ipip.c ++++ b/net/ipv4/ipip.c +@@ -209,13 +209,38 @@ drop: + } + + /* ++ * Determine fan tunnel endpoint to send packet to, based on the inner IP ++ * address. For an overlay (inner) address Y.A.B.C, the transformation is ++ * F.G.A.B, where "F" and "G" are the first two octets of the underlay ++ * network (the network portion of a /16), "A" and "B" are the low order ++ * two octets of the underlay network host (the host portion of a /16), ++ * and "Y" is a configured first octet of the overlay network. ++ * ++ * E.g., underlay host 10.88.3.4 with an overlay of 99 would host overlay ++ * subnet 99.3.4.0/24. An overlay network datagram from 99.3.4.5 to ++ * 99.6.7.8, would be directed to underlay host 10.88.6.7, which hosts ++ * overlay network 99.6.7.0/24. ++ */ ++static void ipip_build_fan_iphdr(struct ip_tunnel *tunnel, struct sk_buff *skb, struct iphdr *iph) ++{ ++ u32 daddr; ++ ++ *iph = tunnel->parms.iph; ++ ++ daddr = ntohl(ip_hdr(skb)->daddr); ++ iph->daddr = htonl((tunnel->fan.underlay & 0xffff0000) | ++ ((daddr >> 8) & 0x0000ffff)); ++} ++ ++/* + * This function assumes it is being called from dev_queue_xmit() + * and that skb is filled properly by that function. + */ + static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) + { + struct ip_tunnel *tunnel = netdev_priv(dev); +- const struct iphdr *tiph = &tunnel->parms.iph; ++ const struct iphdr *tiph; ++ struct iphdr fiph; + + if (unlikely(skb->protocol != htons(ETH_P_IP))) + goto tx_error; +@@ -224,6 +249,13 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) + if (IS_ERR(skb)) + goto out; + ++ if (tunnel->fan.underlay) { ++ ipip_build_fan_iphdr(tunnel, skb, &fiph); ++ tiph = &fiph; ++ } else { ++ tiph = &tunnel->parms.iph; ++ } ++ + skb_set_inner_ipproto(skb, IPPROTO_IPIP); + + ip_tunnel_xmit(skb, dev, tiph, tiph->protocol); +@@ -377,21 +409,44 @@ static bool ipip_netlink_encap_parms(struct nlattr *data[], + return ret; + } + ++static int ipip_netlink_fan(struct nlattr *data[], struct ip_tunnel *t, ++ struct ip_tunnel_parm *parms) ++{ ++ u32 net = t->fan.underlay; ++ ++ if (!data[IFLA_IPTUN_FAN_UNDERLAY]) ++ goto err_check; ++ ++ net = ntohl(nla_get_be32(data[IFLA_IPTUN_FAN_UNDERLAY])) & 0xffff0000; ++ ++err_check: ++ if (parms->iph.daddr && net) ++ return -EINVAL; ++ ++ t->fan.underlay = net; ++ ++ return 0; ++} ++ + static int ipip_newlink(struct net *src_net, struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[]) + { + struct ip_tunnel_parm p; + struct ip_tunnel_encap ipencap; ++ struct ip_tunnel *t = netdev_priv(dev); ++ int err; + + if (ipip_netlink_encap_parms(data, &ipencap)) { +- struct ip_tunnel *t = netdev_priv(dev); +- int err = ip_tunnel_encap_setup(t, &ipencap); ++ err = ip_tunnel_encap_setup(t, &ipencap); + + if (err < 0) + return err; + } + + ipip_netlink_parms(data, &p); ++ err = ipip_netlink_fan(data, t, &p); ++ if (err < 0) ++ return err; + return ip_tunnel_newlink(dev, tb, &p); + } + +@@ -400,16 +455,20 @@ static int ipip_changelink(struct net_device *dev, struct nlattr *tb[], + { + struct ip_tunnel_parm p; + struct ip_tunnel_encap ipencap; ++ struct ip_tunnel *t = netdev_priv(dev); ++ int err; + + if (ipip_netlink_encap_parms(data, &ipencap)) { +- struct ip_tunnel *t = netdev_priv(dev); +- int err = ip_tunnel_encap_setup(t, &ipencap); ++ err = ip_tunnel_encap_setup(t, &ipencap); + + if (err < 0) + return err; + } + + ipip_netlink_parms(data, &p); ++ err = ipip_netlink_fan(data, t, &p); ++ if (err < 0) ++ return err; + + if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) || + (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr)) +@@ -441,6 +500,8 @@ static size_t ipip_get_size(const struct net_device *dev) + nla_total_size(2) + + /* IFLA_IPTUN_ENCAP_DPORT */ + nla_total_size(2) + ++ /* IFLA_IPTUN_FAN_UNDERLAY */ ++ nla_total_size(4) + + 0; + } + +@@ -468,6 +529,11 @@ static int ipip_fill_info(struct sk_buff *skb, const struct net_device *dev) + tunnel->encap.flags)) + goto nla_put_failure; + ++ if (tunnel->fan.underlay) ++ if (nla_put_be32(skb, IFLA_IPTUN_FAN_UNDERLAY, ++ htonl(tunnel->fan.underlay))) ++ goto nla_put_failure; ++ + return 0; + + nla_put_failure: +@@ -485,6 +551,9 @@ static const struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = { + [IFLA_IPTUN_ENCAP_FLAGS] = { .type = NLA_U16 }, + [IFLA_IPTUN_ENCAP_SPORT] = { .type = NLA_U16 }, + [IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 }, ++ ++ [__IFLA_IPTUN_VENDOR_BREAK ... IFLA_IPTUN_MAX] = { .type = NLA_BINARY }, ++ [IFLA_IPTUN_FAN_UNDERLAY] = { .type = NLA_U32 }, + }; + + static struct rtnl_link_ops ipip_link_ops __read_mostly = { +@@ -524,6 +593,23 @@ static struct pernet_operations ipip_net_ops = { + .size = sizeof(struct ip_tunnel_net), + }; + ++#ifdef CONFIG_SYSCTL ++static struct ctl_table_header *ipip_fan_header; ++static unsigned int ipip_fan_version = 1; ++ ++static struct ctl_table ipip_fan_sysctls[] = { ++ { ++ .procname = "version", ++ .data = &ipip_fan_version, ++ .maxlen = sizeof(ipip_fan_version), ++ .mode = 0444, ++ .proc_handler = proc_dointvec, ++ }, ++ {}, ++}; ++ ++#endif /* CONFIG_SYSCTL */ ++ + static int __init ipip_init(void) + { + int err; +@@ -542,9 +628,22 @@ static int __init ipip_init(void) + if (err < 0) + goto rtnl_link_failed; + ++#ifdef CONFIG_SYSCTL ++ ipip_fan_header = register_net_sysctl(&init_net, "net/fan", ++ ipip_fan_sysctls); ++ if (!ipip_fan_header) { ++ err = -ENOMEM; ++ goto sysctl_failed; ++ } ++#endif /* CONFIG_SYSCTL */ ++ + out: + return err; + ++#ifdef CONFIG_SYSCTL ++sysctl_failed: ++ rtnl_link_unregister(&ipip_link_ops); ++#endif /* CONFIG_SYSCTL */ + rtnl_link_failed: + xfrm4_tunnel_deregister(&ipip_handler, AF_INET); + xfrm_tunnel_failed: +@@ -554,6 +653,9 @@ xfrm_tunnel_failed: + + static void __exit ipip_fini(void) + { ++#ifdef CONFIG_SYSCTL ++ unregister_net_sysctl_table(ipip_fan_header); ++#endif /* CONFIG_SYSCTL */ + rtnl_link_unregister(&ipip_link_ops); + if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET)) + pr_info("%s: can't deregister tunnel\n", __func__); +-- +2.4.1 + +From 4ea8011656dfdd76e7a2391bdad47c06f85a9d02 Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Tue, 21 Jul 2015 16:52:10 +0100 +Subject: [PATCH] UBUNTU: SAUCE: fan: tunnel multiple mapping mode (v3) + +Switch to a single tunnel for all mappings, this removes the limitations +on how many mappings each tunnel can handle, and therefore how many Fan +slices each local address may hold. + +NOTE: This introduces a new kernel netlink interface which needs updated +iproute2 support. + +BugLink: http://bugs.launchpad.net/bugs/1470091 +Signed-off-by: Jay Vosburgh +Signed-off-by: Andy Whitcroft +Acked-by: Tim Gardner +Acked-by: Brad Figg +Signed-off-by: Brad Figg +--- + include/net/ip_tunnels.h | 14 ++++- + include/uapi/linux/if_tunnel.h | 20 ++++++- + net/ipv4/ip_tunnel.c | 7 ++- + net/ipv4/ipip.c | 120 +++++++++++++++++++++++++++++++++-------- + 4 files changed, 133 insertions(+), 28 deletions(-) + +diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h +index d7eada2..2f7bc8c 100644 +--- a/include/net/ip_tunnels.h ++++ b/include/net/ip_tunnels.h +@@ -51,9 +51,18 @@ struct ip_tunnel_dst { + __be32 saddr; + }; + +-/* Underlay address prefix for ipip fan mode */ ++/* A fan overlay /8 (250.0.0.0/8, for example) maps to exactly one /16 ++ * underlay (10.88.0.0/16, for example). Multiple local addresses within ++ * the /16 may be used, but a particular overlay may not span ++ * multiple underlay subnets. ++ * ++ * We store one underlay, indexed by the overlay's high order octet. ++ */ ++#define FAN_OVERLAY_CNT 256 ++ + struct ip_tunnel_fan { +- u32 underlay; ++/* u32 __rcu *map;*/ ++ u32 map[FAN_OVERLAY_CNT]; + }; + + struct ip_tunnel { +@@ -104,6 +113,7 @@ struct ip_tunnel { + #define TUNNEL_OAM __cpu_to_be16(0x0200) + #define TUNNEL_CRIT_OPT __cpu_to_be16(0x0400) + #define TUNNEL_OPTIONS_PRESENT __cpu_to_be16(0x0800) ++#define TUNNEL_FAN __cpu_to_be16(0x4000) + + struct tnl_ptk_info { + __be16 flags; +diff --git a/include/uapi/linux/if_tunnel.h b/include/uapi/linux/if_tunnel.h +index 8f7d269..9625934 100644 +--- a/include/uapi/linux/if_tunnel.h ++++ b/include/uapi/linux/if_tunnel.h +@@ -58,8 +58,8 @@ enum { + IFLA_IPTUN_ENCAP_SPORT, + IFLA_IPTUN_ENCAP_DPORT, + +- __IFLA_IPTUN_VENDOR_BREAK, /* Ensure new entries do not hit the below. */ +- IFLA_IPTUN_FAN_UNDERLAY=32, ++ __IFLA_IPTUN_VENDOR_BREAK, /* Ensure new entries do not hit the below. */ ++ IFLA_IPTUN_FAN_MAP = 33, + + __IFLA_IPTUN_MAX, + }; +@@ -135,4 +135,20 @@ enum { + }; + + #define IFLA_VTI_MAX (__IFLA_VTI_MAX - 1) ++ ++enum { ++ IFLA_FAN_UNSPEC, ++ IFLA_FAN_MAPPING, ++ __IFLA_FAN_MAX, ++}; ++ ++#define IFLA_FAN_MAX (__IFLA_FAN_MAX - 1) ++ ++struct ip_tunnel_fan_map { ++ __be32 underlay; ++ __be32 overlay; ++ __u16 underlay_prefix; ++ __u16 overlay_prefix; ++}; ++ + #endif /* _UAPI_IF_TUNNEL_H_ */ +diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c +index d3e4479..60bd10f 100644 +--- a/net/ipv4/ip_tunnel.c ++++ b/net/ipv4/ip_tunnel.c +@@ -1078,6 +1078,11 @@ out: + } + EXPORT_SYMBOL_GPL(ip_tunnel_newlink); + ++static int ip_tunnel_is_fan(struct ip_tunnel *tunnel) ++{ ++ return tunnel->parms.i_flags & TUNNEL_FAN; ++} ++ + int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[], + struct ip_tunnel_parm *p) + { +@@ -1087,7 +1092,7 @@ int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[], + struct ip_tunnel_net *itn = net_generic(net, tunnel->ip_tnl_net_id); + + if (dev == itn->fb_tunnel_dev) +- return -EINVAL; ++ return ip_tunnel_is_fan(tunnel) ? 0 : -EINVAL; + + t = ip_tunnel_find(itn, p, dev->type); + +diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c +index e3c27cd..d6ebc66 100644 +--- a/net/ipv4/ipip.c ++++ b/net/ipv4/ipip.c +@@ -107,6 +107,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -208,6 +209,11 @@ drop: + return 0; + } + ++static int ipip_tunnel_is_fan(struct ip_tunnel *tunnel) ++{ ++ return tunnel->parms.i_flags & TUNNEL_FAN; ++} ++ + /* + * Determine fan tunnel endpoint to send packet to, based on the inner IP + * address. For an overlay (inner) address Y.A.B.C, the transformation is +@@ -221,15 +227,20 @@ drop: + * 99.6.7.8, would be directed to underlay host 10.88.6.7, which hosts + * overlay network 99.6.7.0/24. + */ +-static void ipip_build_fan_iphdr(struct ip_tunnel *tunnel, struct sk_buff *skb, struct iphdr *iph) ++static int ipip_build_fan_iphdr(struct ip_tunnel *tunnel, struct sk_buff *skb, struct iphdr *iph) + { +- u32 daddr; +- +- *iph = tunnel->parms.iph; ++ unsigned int overlay; ++ u32 daddr, underlay; + + daddr = ntohl(ip_hdr(skb)->daddr); +- iph->daddr = htonl((tunnel->fan.underlay & 0xffff0000) | +- ((daddr >> 8) & 0x0000ffff)); ++ overlay = daddr >> 24; ++ underlay = tunnel->fan.map[overlay]; ++ if (!underlay) ++ return -EINVAL; ++ ++ *iph = tunnel->parms.iph; ++ iph->daddr = htonl(underlay | ((daddr >> 8) & 0x0000ffff)); ++ return 0; + } + + /* +@@ -249,8 +260,9 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) + if (IS_ERR(skb)) + goto out; + +- if (tunnel->fan.underlay) { +- ipip_build_fan_iphdr(tunnel, skb, &fiph); ++ if (ipip_tunnel_is_fan(tunnel)) { ++ if (ipip_build_fan_iphdr(tunnel, skb, &fiph)) ++ goto tx_error; + tiph = &fiph; + } else { + tiph = &tunnel->parms.iph; +@@ -409,21 +421,65 @@ static bool ipip_netlink_encap_parms(struct nlattr *data[], + return ret; + } + ++static void ipip_fan_free_map(struct ip_tunnel *t) ++{ ++ memset(&t->fan.map, 0, sizeof(t->fan.map)); ++} ++ ++static int ipip_fan_set_map(struct ip_tunnel *t, struct ip_tunnel_fan_map *map) ++{ ++ u32 overlay, overlay_mask, underlay, underlay_mask; ++ ++ if ((map->underlay_prefix && map->underlay_prefix != 16) || ++ (map->overlay_prefix && map->overlay_prefix != 8)) ++ return -EINVAL; ++ ++ overlay = ntohl(map->overlay); ++ overlay_mask = ntohl(inet_make_mask(map->overlay_prefix)); ++ ++ underlay = ntohl(map->underlay); ++ underlay_mask = ntohl(inet_make_mask(map->underlay_prefix)); ++ ++ if ((overlay & ~overlay_mask) || (underlay & ~underlay_mask)) ++ return -EINVAL; ++ ++ if (!(overlay & overlay_mask) && (underlay & underlay_mask)) ++ return -EINVAL; ++ ++ t->parms.i_flags |= TUNNEL_FAN; ++ ++ /* Special case: overlay 0 and underlay 0 clears all mappings */ ++ if (!overlay && !underlay) { ++ ipip_fan_free_map(t); ++ return 0; ++ } ++ ++ overlay >>= (32 - map->overlay_prefix); ++ t->fan.map[overlay] = underlay; ++ ++ return 0; ++} ++ ++ + static int ipip_netlink_fan(struct nlattr *data[], struct ip_tunnel *t, + struct ip_tunnel_parm *parms) + { +- u32 net = t->fan.underlay; +- +- if (!data[IFLA_IPTUN_FAN_UNDERLAY]) +- goto err_check; ++ struct ip_tunnel_fan_map *map; ++ struct nlattr *attr; ++ int rem, rv; + +- net = ntohl(nla_get_be32(data[IFLA_IPTUN_FAN_UNDERLAY])) & 0xffff0000; ++ if (!data[IFLA_IPTUN_FAN_MAP]) ++ return 0; + +-err_check: +- if (parms->iph.daddr && net) ++ if (parms->iph.daddr) + return -EINVAL; + +- t->fan.underlay = net; ++ nla_for_each_nested(attr, data[IFLA_IPTUN_FAN_MAP], rem) { ++ map = nla_data(attr); ++ rv = ipip_fan_set_map(t, map); ++ if (rv) ++ return rv; ++ } + + return 0; + } +@@ -500,8 +556,8 @@ static size_t ipip_get_size(const struct net_device *dev) + nla_total_size(2) + + /* IFLA_IPTUN_ENCAP_DPORT */ + nla_total_size(2) + +- /* IFLA_IPTUN_FAN_UNDERLAY */ +- nla_total_size(4) + ++ /* IFLA_IPTUN_FAN_MAP */ ++ nla_total_size(sizeof(struct ip_tunnel_fan_map)) * 256 + + 0; + } + +@@ -529,10 +585,28 @@ static int ipip_fill_info(struct sk_buff *skb, const struct net_device *dev) + tunnel->encap.flags)) + goto nla_put_failure; + +- if (tunnel->fan.underlay) +- if (nla_put_be32(skb, IFLA_IPTUN_FAN_UNDERLAY, +- htonl(tunnel->fan.underlay))) ++ if (tunnel->parms.i_flags & TUNNEL_FAN) { ++ struct nlattr *fan_nest; ++ int i; ++ ++ fan_nest = nla_nest_start(skb, IFLA_IPTUN_FAN_MAP); ++ if (!fan_nest) + goto nla_put_failure; ++ for (i = 0; i < 256; i++) { ++ if (tunnel->fan.map[i]) { ++ struct ip_tunnel_fan_map map; ++ ++ map.underlay = htonl(tunnel->fan.map[i]); ++ map.underlay_prefix = 16; ++ map.overlay = htonl(i << 24); ++ map.overlay_prefix = 8; ++ if (nla_put(skb, IFLA_FAN_MAPPING, ++ sizeof(map), &map)) ++ goto nla_put_failure; ++ } ++ } ++ nla_nest_end(skb, fan_nest); ++ } + + return 0; + +@@ -553,7 +627,7 @@ static const struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = { + [IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 }, + + [__IFLA_IPTUN_VENDOR_BREAK ... IFLA_IPTUN_MAX] = { .type = NLA_BINARY }, +- [IFLA_IPTUN_FAN_UNDERLAY] = { .type = NLA_U32 }, ++ [IFLA_IPTUN_FAN_MAP] = { .type = NLA_NESTED }, + }; + + static struct rtnl_link_ops ipip_link_ops __read_mostly = { +@@ -595,7 +669,7 @@ static struct pernet_operations ipip_net_ops = { + + #ifdef CONFIG_SYSCTL + static struct ctl_table_header *ipip_fan_header; +-static unsigned int ipip_fan_version = 1; ++static unsigned int ipip_fan_version = 3; + + static struct ctl_table ipip_fan_sysctls[] = { + { +-- +2.4.1 + diff --git a/pkgs/os-specific/linux/kernel/ubuntu-fan-4.patch b/pkgs/os-specific/linux/kernel/ubuntu-fan-4.patch new file mode 100644 index 000000000000..0050af6c2527 --- /dev/null +++ b/pkgs/os-specific/linux/kernel/ubuntu-fan-4.patch @@ -0,0 +1,616 @@ +From f3c956096902669c3529cb01d40deb0c759ed94f Mon Sep 17 00:00:00 2001 +From: Jay Vosburgh +Date: Wed, 1 Apr 2015 16:11:09 -0700 +Subject: [PATCH] UBUNTU: SAUCE: fan: Proof of concept implementation (v2) + +Modification to ipip tunnel driver to accept a new netlink option, +IFLA_IPTUN_FAN_UNDERLAY, which provides a /16 network prefix and enables +TX side destination address remapping for traffic entering the tunnel +(to be encapsulated). + +For an overlay (inner) address Y.A.B.C, the transformation is F.G.A.B, +where "F" and "G" are the first two octets of the underlay network (the +network portion of a /16), "A" and "B" are the low order two octets of the +underlay network host (the host portion of a /16), and "Y" is a configured +first octet of the overlay network. + +E.g., underlay host 10.88.3.4 with an overlay of 99 would host overlay +subnet 99.3.4.0/24. An overlay network datagram from 99.3.4.5 to 99.6.7.8 +would be directed to underlay host 10.88.6.7, which hosts overlay network +99.6.7.0/24. + +Includes net.fan.version sysctl as a sentinel for availability of the +fan functionality. + +NOTE: this requires an updated iproute2 to facilitate configuration of +the fan. + +BugLink: http://bugs.launchpad.net/bugs/1439706 +Signed-off-by: Jay Vosburgh +[apw@canonical.com: move IFLA_IPTUN_FAN_UNDERLAY up to avoid clashing + with future feature additions.] +Signed-off-by: Andy Whitcroft +--- + include/net/ip_tunnels.h | 6 +++ + include/uapi/linux/if_tunnel.h | 4 ++ + net/ipv4/ipip.c | 112 +++++++++++++++++++++++++++++++++++++++-- + 3 files changed, 117 insertions(+), 5 deletions(-) + +diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h +index 25a59eb..d7eada2 100644 +--- a/include/net/ip_tunnels.h ++++ b/include/net/ip_tunnels.h +@@ -51,6 +51,11 @@ struct ip_tunnel_dst { + __be32 saddr; + }; + ++/* Underlay address prefix for ipip fan mode */ ++struct ip_tunnel_fan { ++ u32 underlay; ++}; ++ + struct ip_tunnel { + struct ip_tunnel __rcu *next; + struct hlist_node hash_node; +@@ -82,6 +87,7 @@ struct ip_tunnel { + #endif + struct ip_tunnel_prl_entry __rcu *prl; /* potential router list */ + unsigned int prl_count; /* # of entries in PRL */ ++ struct ip_tunnel_fan fan; + int ip_tnl_net_id; + struct gro_cells gro_cells; + }; +diff --git a/include/uapi/linux/if_tunnel.h b/include/uapi/linux/if_tunnel.h +index bd3cc11..8f7d269 100644 +--- a/include/uapi/linux/if_tunnel.h ++++ b/include/uapi/linux/if_tunnel.h +@@ -57,6 +57,10 @@ enum { + IFLA_IPTUN_ENCAP_FLAGS, + IFLA_IPTUN_ENCAP_SPORT, + IFLA_IPTUN_ENCAP_DPORT, ++ ++ __IFLA_IPTUN_VENDOR_BREAK, /* Ensure new entries do not hit the below. */ ++ IFLA_IPTUN_FAN_UNDERLAY=32, ++ + __IFLA_IPTUN_MAX, + }; + #define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1) +diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c +index 40403114..e3c27cd 100644 +--- a/net/ipv4/ipip.c ++++ b/net/ipv4/ipip.c +@@ -209,13 +209,38 @@ drop: + } + + /* ++ * Determine fan tunnel endpoint to send packet to, based on the inner IP ++ * address. For an overlay (inner) address Y.A.B.C, the transformation is ++ * F.G.A.B, where "F" and "G" are the first two octets of the underlay ++ * network (the network portion of a /16), "A" and "B" are the low order ++ * two octets of the underlay network host (the host portion of a /16), ++ * and "Y" is a configured first octet of the overlay network. ++ * ++ * E.g., underlay host 10.88.3.4 with an overlay of 99 would host overlay ++ * subnet 99.3.4.0/24. An overlay network datagram from 99.3.4.5 to ++ * 99.6.7.8, would be directed to underlay host 10.88.6.7, which hosts ++ * overlay network 99.6.7.0/24. ++ */ ++static void ipip_build_fan_iphdr(struct ip_tunnel *tunnel, struct sk_buff *skb, struct iphdr *iph) ++{ ++ u32 daddr; ++ ++ *iph = tunnel->parms.iph; ++ ++ daddr = ntohl(ip_hdr(skb)->daddr); ++ iph->daddr = htonl((tunnel->fan.underlay & 0xffff0000) | ++ ((daddr >> 8) & 0x0000ffff)); ++} ++ ++/* + * This function assumes it is being called from dev_queue_xmit() + * and that skb is filled properly by that function. + */ + static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) + { + struct ip_tunnel *tunnel = netdev_priv(dev); +- const struct iphdr *tiph = &tunnel->parms.iph; ++ const struct iphdr *tiph; ++ struct iphdr fiph; + + if (unlikely(skb->protocol != htons(ETH_P_IP))) + goto tx_error; +@@ -224,6 +249,13 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) + if (IS_ERR(skb)) + goto out; + ++ if (tunnel->fan.underlay) { ++ ipip_build_fan_iphdr(tunnel, skb, &fiph); ++ tiph = &fiph; ++ } else { ++ tiph = &tunnel->parms.iph; ++ } ++ + skb_set_inner_ipproto(skb, IPPROTO_IPIP); + + ip_tunnel_xmit(skb, dev, tiph, tiph->protocol); +@@ -377,21 +409,44 @@ static bool ipip_netlink_encap_parms(struct nlattr *data[], + return ret; + } + ++static int ipip_netlink_fan(struct nlattr *data[], struct ip_tunnel *t, ++ struct ip_tunnel_parm *parms) ++{ ++ u32 net = t->fan.underlay; ++ ++ if (!data[IFLA_IPTUN_FAN_UNDERLAY]) ++ goto err_check; ++ ++ net = ntohl(nla_get_be32(data[IFLA_IPTUN_FAN_UNDERLAY])) & 0xffff0000; ++ ++err_check: ++ if (parms->iph.daddr && net) ++ return -EINVAL; ++ ++ t->fan.underlay = net; ++ ++ return 0; ++} ++ + static int ipip_newlink(struct net *src_net, struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[]) + { + struct ip_tunnel_parm p; + struct ip_tunnel_encap ipencap; ++ struct ip_tunnel *t = netdev_priv(dev); ++ int err; + + if (ipip_netlink_encap_parms(data, &ipencap)) { +- struct ip_tunnel *t = netdev_priv(dev); +- int err = ip_tunnel_encap_setup(t, &ipencap); ++ err = ip_tunnel_encap_setup(t, &ipencap); + + if (err < 0) + return err; + } + + ipip_netlink_parms(data, &p); ++ err = ipip_netlink_fan(data, t, &p); ++ if (err < 0) ++ return err; + return ip_tunnel_newlink(dev, tb, &p); + } + +@@ -400,16 +455,20 @@ static int ipip_changelink(struct net_device *dev, struct nlattr *tb[], + { + struct ip_tunnel_parm p; + struct ip_tunnel_encap ipencap; ++ struct ip_tunnel *t = netdev_priv(dev); ++ int err; + + if (ipip_netlink_encap_parms(data, &ipencap)) { +- struct ip_tunnel *t = netdev_priv(dev); +- int err = ip_tunnel_encap_setup(t, &ipencap); ++ err = ip_tunnel_encap_setup(t, &ipencap); + + if (err < 0) + return err; + } + + ipip_netlink_parms(data, &p); ++ err = ipip_netlink_fan(data, t, &p); ++ if (err < 0) ++ return err; + + if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) || + (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr)) +@@ -441,6 +500,8 @@ static size_t ipip_get_size(const struct net_device *dev) + nla_total_size(2) + + /* IFLA_IPTUN_ENCAP_DPORT */ + nla_total_size(2) + ++ /* IFLA_IPTUN_FAN_UNDERLAY */ ++ nla_total_size(4) + + 0; + } + +@@ -468,6 +529,11 @@ static int ipip_fill_info(struct sk_buff *skb, const struct net_device *dev) + tunnel->encap.flags)) + goto nla_put_failure; + ++ if (tunnel->fan.underlay) ++ if (nla_put_be32(skb, IFLA_IPTUN_FAN_UNDERLAY, ++ htonl(tunnel->fan.underlay))) ++ goto nla_put_failure; ++ + return 0; + + nla_put_failure: +@@ -485,6 +551,9 @@ static const struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = { + [IFLA_IPTUN_ENCAP_FLAGS] = { .type = NLA_U16 }, + [IFLA_IPTUN_ENCAP_SPORT] = { .type = NLA_U16 }, + [IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 }, ++ ++ [__IFLA_IPTUN_VENDOR_BREAK ... IFLA_IPTUN_MAX] = { .type = NLA_BINARY }, ++ [IFLA_IPTUN_FAN_UNDERLAY] = { .type = NLA_U32 }, + }; + + static struct rtnl_link_ops ipip_link_ops __read_mostly = { +@@ -524,6 +593,23 @@ static struct pernet_operations ipip_net_ops = { + .size = sizeof(struct ip_tunnel_net), + }; + ++#ifdef CONFIG_SYSCTL ++static struct ctl_table_header *ipip_fan_header; ++static unsigned int ipip_fan_version = 1; ++ ++static struct ctl_table ipip_fan_sysctls[] = { ++ { ++ .procname = "version", ++ .data = &ipip_fan_version, ++ .maxlen = sizeof(ipip_fan_version), ++ .mode = 0444, ++ .proc_handler = proc_dointvec, ++ }, ++ {}, ++}; ++ ++#endif /* CONFIG_SYSCTL */ ++ + static int __init ipip_init(void) + { + int err; +@@ -542,9 +628,22 @@ static int __init ipip_init(void) + if (err < 0) + goto rtnl_link_failed; + ++#ifdef CONFIG_SYSCTL ++ ipip_fan_header = register_net_sysctl(&init_net, "net/fan", ++ ipip_fan_sysctls); ++ if (!ipip_fan_header) { ++ err = -ENOMEM; ++ goto sysctl_failed; ++ } ++#endif /* CONFIG_SYSCTL */ ++ + out: + return err; + ++#ifdef CONFIG_SYSCTL ++sysctl_failed: ++ rtnl_link_unregister(&ipip_link_ops); ++#endif /* CONFIG_SYSCTL */ + rtnl_link_failed: + xfrm4_tunnel_deregister(&ipip_handler, AF_INET); + xfrm_tunnel_failed: +@@ -554,6 +653,9 @@ xfrm_tunnel_failed: + + static void __exit ipip_fini(void) + { ++#ifdef CONFIG_SYSCTL ++ unregister_net_sysctl_table(ipip_fan_header); ++#endif /* CONFIG_SYSCTL */ + rtnl_link_unregister(&ipip_link_ops); + if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET)) + pr_info("%s: can't deregister tunnel\n", __func__); +-- +2.4.1 + +From 4ea8011656dfdd76e7a2391bdad47c06f85a9d02 Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Tue, 21 Jul 2015 16:52:10 +0100 +Subject: [PATCH] UBUNTU: SAUCE: fan: tunnel multiple mapping mode (v3) + +Switch to a single tunnel for all mappings, this removes the limitations +on how many mappings each tunnel can handle, and therefore how many Fan +slices each local address may hold. + +NOTE: This introduces a new kernel netlink interface which needs updated +iproute2 support. + +BugLink: http://bugs.launchpad.net/bugs/1470091 +Signed-off-by: Jay Vosburgh +Signed-off-by: Andy Whitcroft +Acked-by: Tim Gardner +Acked-by: Brad Figg +Signed-off-by: Brad Figg +--- + include/net/ip_tunnels.h | 14 ++++- + include/uapi/linux/if_tunnel.h | 20 ++++++- + net/ipv4/ip_tunnel.c | 7 ++- + net/ipv4/ipip.c | 120 +++++++++++++++++++++++++++++++++-------- + 4 files changed, 133 insertions(+), 28 deletions(-) + +diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h +index d7eada2..2f7bc8c 100644 +--- a/include/net/ip_tunnels.h ++++ b/include/net/ip_tunnels.h +@@ -51,9 +51,18 @@ struct ip_tunnel_dst { + __be32 saddr; + }; + +-/* Underlay address prefix for ipip fan mode */ ++/* A fan overlay /8 (250.0.0.0/8, for example) maps to exactly one /16 ++ * underlay (10.88.0.0/16, for example). Multiple local addresses within ++ * the /16 may be used, but a particular overlay may not span ++ * multiple underlay subnets. ++ * ++ * We store one underlay, indexed by the overlay's high order octet. ++ */ ++#define FAN_OVERLAY_CNT 256 ++ + struct ip_tunnel_fan { +- u32 underlay; ++/* u32 __rcu *map;*/ ++ u32 map[FAN_OVERLAY_CNT]; + }; + + struct ip_tunnel { +@@ -104,6 +113,7 @@ struct ip_tunnel { + #define TUNNEL_OAM __cpu_to_be16(0x0200) + #define TUNNEL_CRIT_OPT __cpu_to_be16(0x0400) + #define TUNNEL_GENEVE_OPT __cpu_to_be16(0x0800) + #define TUNNEL_VXLAN_OPT __cpu_to_be16(0x1000) ++#define TUNNEL_FAN __cpu_to_be16(0x4000) + + #define TUNNEL_OPTIONS_PRESENT (TUNNEL_GENEVE_OPT | TUNNEL_VXLAN_OPT) +diff --git a/include/uapi/linux/if_tunnel.h b/include/uapi/linux/if_tunnel.h +index 8f7d269..9625934 100644 +--- a/include/uapi/linux/if_tunnel.h ++++ b/include/uapi/linux/if_tunnel.h +@@ -58,8 +58,8 @@ enum { + IFLA_IPTUN_ENCAP_SPORT, + IFLA_IPTUN_ENCAP_DPORT, + +- __IFLA_IPTUN_VENDOR_BREAK, /* Ensure new entries do not hit the below. */ +- IFLA_IPTUN_FAN_UNDERLAY=32, ++ __IFLA_IPTUN_VENDOR_BREAK, /* Ensure new entries do not hit the below. */ ++ IFLA_IPTUN_FAN_MAP = 33, + + __IFLA_IPTUN_MAX, + }; +@@ -135,4 +135,20 @@ enum { + }; + + #define IFLA_VTI_MAX (__IFLA_VTI_MAX - 1) ++ ++enum { ++ IFLA_FAN_UNSPEC, ++ IFLA_FAN_MAPPING, ++ __IFLA_FAN_MAX, ++}; ++ ++#define IFLA_FAN_MAX (__IFLA_FAN_MAX - 1) ++ ++struct ip_tunnel_fan_map { ++ __be32 underlay; ++ __be32 overlay; ++ __u16 underlay_prefix; ++ __u16 overlay_prefix; ++}; ++ + #endif /* _UAPI_IF_TUNNEL_H_ */ +diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c +index d3e4479..60bd10f 100644 +--- a/net/ipv4/ip_tunnel.c ++++ b/net/ipv4/ip_tunnel.c +@@ -1078,6 +1078,11 @@ out: + } + EXPORT_SYMBOL_GPL(ip_tunnel_newlink); + ++static int ip_tunnel_is_fan(struct ip_tunnel *tunnel) ++{ ++ return tunnel->parms.i_flags & TUNNEL_FAN; ++} ++ + int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[], + struct ip_tunnel_parm *p) + { +@@ -1087,7 +1092,7 @@ int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[], + struct ip_tunnel_net *itn = net_generic(net, tunnel->ip_tnl_net_id); + + if (dev == itn->fb_tunnel_dev) +- return -EINVAL; ++ return ip_tunnel_is_fan(tunnel) ? 0 : -EINVAL; + + t = ip_tunnel_find(itn, p, dev->type); + +diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c +index e3c27cd..d6ebc66 100644 +--- a/net/ipv4/ipip.c ++++ b/net/ipv4/ipip.c +@@ -107,6 +107,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -208,6 +209,11 @@ drop: + return 0; + } + ++static int ipip_tunnel_is_fan(struct ip_tunnel *tunnel) ++{ ++ return tunnel->parms.i_flags & TUNNEL_FAN; ++} ++ + /* + * Determine fan tunnel endpoint to send packet to, based on the inner IP + * address. For an overlay (inner) address Y.A.B.C, the transformation is +@@ -221,15 +227,20 @@ drop: + * 99.6.7.8, would be directed to underlay host 10.88.6.7, which hosts + * overlay network 99.6.7.0/24. + */ +-static void ipip_build_fan_iphdr(struct ip_tunnel *tunnel, struct sk_buff *skb, struct iphdr *iph) ++static int ipip_build_fan_iphdr(struct ip_tunnel *tunnel, struct sk_buff *skb, struct iphdr *iph) + { +- u32 daddr; +- +- *iph = tunnel->parms.iph; ++ unsigned int overlay; ++ u32 daddr, underlay; + + daddr = ntohl(ip_hdr(skb)->daddr); +- iph->daddr = htonl((tunnel->fan.underlay & 0xffff0000) | +- ((daddr >> 8) & 0x0000ffff)); ++ overlay = daddr >> 24; ++ underlay = tunnel->fan.map[overlay]; ++ if (!underlay) ++ return -EINVAL; ++ ++ *iph = tunnel->parms.iph; ++ iph->daddr = htonl(underlay | ((daddr >> 8) & 0x0000ffff)); ++ return 0; + } + + /* +@@ -249,8 +260,9 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) + if (IS_ERR(skb)) + goto out; + +- if (tunnel->fan.underlay) { +- ipip_build_fan_iphdr(tunnel, skb, &fiph); ++ if (ipip_tunnel_is_fan(tunnel)) { ++ if (ipip_build_fan_iphdr(tunnel, skb, &fiph)) ++ goto tx_error; + tiph = &fiph; + } else { + tiph = &tunnel->parms.iph; +@@ -409,21 +421,65 @@ static bool ipip_netlink_encap_parms(struct nlattr *data[], + return ret; + } + ++static void ipip_fan_free_map(struct ip_tunnel *t) ++{ ++ memset(&t->fan.map, 0, sizeof(t->fan.map)); ++} ++ ++static int ipip_fan_set_map(struct ip_tunnel *t, struct ip_tunnel_fan_map *map) ++{ ++ u32 overlay, overlay_mask, underlay, underlay_mask; ++ ++ if ((map->underlay_prefix && map->underlay_prefix != 16) || ++ (map->overlay_prefix && map->overlay_prefix != 8)) ++ return -EINVAL; ++ ++ overlay = ntohl(map->overlay); ++ overlay_mask = ntohl(inet_make_mask(map->overlay_prefix)); ++ ++ underlay = ntohl(map->underlay); ++ underlay_mask = ntohl(inet_make_mask(map->underlay_prefix)); ++ ++ if ((overlay & ~overlay_mask) || (underlay & ~underlay_mask)) ++ return -EINVAL; ++ ++ if (!(overlay & overlay_mask) && (underlay & underlay_mask)) ++ return -EINVAL; ++ ++ t->parms.i_flags |= TUNNEL_FAN; ++ ++ /* Special case: overlay 0 and underlay 0 clears all mappings */ ++ if (!overlay && !underlay) { ++ ipip_fan_free_map(t); ++ return 0; ++ } ++ ++ overlay >>= (32 - map->overlay_prefix); ++ t->fan.map[overlay] = underlay; ++ ++ return 0; ++} ++ ++ + static int ipip_netlink_fan(struct nlattr *data[], struct ip_tunnel *t, + struct ip_tunnel_parm *parms) + { +- u32 net = t->fan.underlay; +- +- if (!data[IFLA_IPTUN_FAN_UNDERLAY]) +- goto err_check; ++ struct ip_tunnel_fan_map *map; ++ struct nlattr *attr; ++ int rem, rv; + +- net = ntohl(nla_get_be32(data[IFLA_IPTUN_FAN_UNDERLAY])) & 0xffff0000; ++ if (!data[IFLA_IPTUN_FAN_MAP]) ++ return 0; + +-err_check: +- if (parms->iph.daddr && net) ++ if (parms->iph.daddr) + return -EINVAL; + +- t->fan.underlay = net; ++ nla_for_each_nested(attr, data[IFLA_IPTUN_FAN_MAP], rem) { ++ map = nla_data(attr); ++ rv = ipip_fan_set_map(t, map); ++ if (rv) ++ return rv; ++ } + + return 0; + } +@@ -500,8 +556,8 @@ static size_t ipip_get_size(const struct net_device *dev) + nla_total_size(2) + + /* IFLA_IPTUN_ENCAP_DPORT */ + nla_total_size(2) + +- /* IFLA_IPTUN_FAN_UNDERLAY */ +- nla_total_size(4) + ++ /* IFLA_IPTUN_FAN_MAP */ ++ nla_total_size(sizeof(struct ip_tunnel_fan_map)) * 256 + + 0; + } + +@@ -529,10 +585,28 @@ static int ipip_fill_info(struct sk_buff *skb, const struct net_device *dev) + tunnel->encap.flags)) + goto nla_put_failure; + +- if (tunnel->fan.underlay) +- if (nla_put_be32(skb, IFLA_IPTUN_FAN_UNDERLAY, +- htonl(tunnel->fan.underlay))) ++ if (tunnel->parms.i_flags & TUNNEL_FAN) { ++ struct nlattr *fan_nest; ++ int i; ++ ++ fan_nest = nla_nest_start(skb, IFLA_IPTUN_FAN_MAP); ++ if (!fan_nest) + goto nla_put_failure; ++ for (i = 0; i < 256; i++) { ++ if (tunnel->fan.map[i]) { ++ struct ip_tunnel_fan_map map; ++ ++ map.underlay = htonl(tunnel->fan.map[i]); ++ map.underlay_prefix = 16; ++ map.overlay = htonl(i << 24); ++ map.overlay_prefix = 8; ++ if (nla_put(skb, IFLA_FAN_MAPPING, ++ sizeof(map), &map)) ++ goto nla_put_failure; ++ } ++ } ++ nla_nest_end(skb, fan_nest); ++ } + + return 0; + +@@ -553,7 +627,7 @@ static const struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = { + [IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 }, + + [__IFLA_IPTUN_VENDOR_BREAK ... IFLA_IPTUN_MAX] = { .type = NLA_BINARY }, +- [IFLA_IPTUN_FAN_UNDERLAY] = { .type = NLA_U32 }, ++ [IFLA_IPTUN_FAN_MAP] = { .type = NLA_NESTED }, + }; + + static struct rtnl_link_ops ipip_link_ops __read_mostly = { +@@ -595,7 +669,7 @@ static struct pernet_operations ipip_net_ops = { + + #ifdef CONFIG_SYSCTL + static struct ctl_table_header *ipip_fan_header; +-static unsigned int ipip_fan_version = 1; ++static unsigned int ipip_fan_version = 3; + + static struct ctl_table ipip_fan_sysctls[] = { + { +-- +2.4.1 + diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 3e34e61cebfc..ea73c4a881fe 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -9556,6 +9556,10 @@ let eject = utillinux; + fanctl = callPackage ../os-specific/linux/fanctl { + iproute = iproute.override { enableFan = true; }; + }; + fatrace = callPackage ../os-specific/linux/fatrace { }; ffadoFull = callPackage ../os-specific/linux/ffado { };