From ad7b1e24c20d60199525f3849115fa7e96bc5174 Mon Sep 17 00:00:00 2001 From: Charles Strahan Date: Sat, 9 Apr 2016 19:36:02 -0400 Subject: fan-networking: updated patches from Ubuntu This pulls in updated Fan Networking patches from Ubuntu. (https://wiki.ubuntu.com/FanNetworking) closes #14328 --- pkgs/os-specific/linux/fanctl/default.nix | 46 +- pkgs/os-specific/linux/fanctl/robustness.patch | 85 ++ .../linux/iproute/1000-ubuntu-poc-fan-driver.patch | 65 + .../iproute/1001-ubuntu-poc-fan-driver-v3.patch | 133 +++ .../iproute/1002-ubuntu-poc-fan-driver-vxlan.patch | 177 +++ pkgs/os-specific/linux/iproute/default.nix | 8 +- pkgs/os-specific/linux/iproute/ubuntu-fan.patch | 164 --- pkgs/os-specific/linux/kernel/patches.nix | 9 +- pkgs/os-specific/linux/kernel/ubuntu-fan-3.patch | 616 ---------- pkgs/os-specific/linux/kernel/ubuntu-fan-4.4.patch | 1240 ++++++++++++++++++++ pkgs/os-specific/linux/kernel/ubuntu-fan-4.patch | 616 ---------- 11 files changed, 1731 insertions(+), 1428 deletions(-) create mode 100644 pkgs/os-specific/linux/fanctl/robustness.patch create mode 100644 pkgs/os-specific/linux/iproute/1000-ubuntu-poc-fan-driver.patch create mode 100644 pkgs/os-specific/linux/iproute/1001-ubuntu-poc-fan-driver-v3.patch create mode 100644 pkgs/os-specific/linux/iproute/1002-ubuntu-poc-fan-driver-vxlan.patch delete mode 100644 pkgs/os-specific/linux/iproute/ubuntu-fan.patch delete mode 100644 pkgs/os-specific/linux/kernel/ubuntu-fan-3.patch create mode 100644 pkgs/os-specific/linux/kernel/ubuntu-fan-4.4.patch delete mode 100644 pkgs/os-specific/linux/kernel/ubuntu-fan-4.patch diff --git a/pkgs/os-specific/linux/fanctl/default.nix b/pkgs/os-specific/linux/fanctl/default.nix index 61e100f4c9b..cb188b56c06 100644 --- a/pkgs/os-specific/linux/fanctl/default.nix +++ b/pkgs/os-specific/linux/fanctl/default.nix @@ -1,41 +1,39 @@ -{ stdenv, lib, fetchbzr, makeWrapper, bridge-utils, iproute, dnsmasq, iptables, kmod, utillinux }: +{ stdenv, lib, fetchurl, gnugrep, glibc, gawk, coreutils, bridge-utils, iproute +, dnsmasq, iptables, kmod, utillinux, gnused }: -let stateDir = "/var/lib/fan-networking"; -in stdenv.mkDerivation rec { +stdenv.mkDerivation rec { name = "fanctl-${version}"; - version = "0.3.0"; + version = "0.9.0"; - src = fetchbzr { - url = "https://code.launchpad.net/~ubuntu-branches/ubuntu/vivid/ubuntu-fan/vivid-updates"; - rev = 2; - sha256 = "1vcr2rg99g7sx1zynhiggjzc9y9z591i4535hbm21dysy3cisp7i"; + src = fetchurl { + url = "https://launchpad.net/ubuntu/+archive/primary/+files/ubuntu-fan_${version}.tar.xz"; + sha256 = "03dv5zzb8fkl9kkbhznxm48d6j3fjms74fn0s1zip2gz53l1s14n"; }; - buildInputs = [ makeWrapper ]; + # The Ubuntu package creates a number of state/config directories upon + # installation, and so the fanctl script expects those directories to exist + # before being used. Instead, we patch the fanctl script to gracefully handle + # the fact that the directories might not exist yet. + # Also, when dnsmasq is given --conf-file="", it will still attempt to read + # /etc/dnsmasq.conf; if that file does not exist, dnsmasq subsequently fails, + # so we'll use /dev/null, which actually works as intended. + patches = [ ./robustness.patch ]; - # 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 the state directory before starting dnsmasq. - buildPhase = '' + postPatch = '' substituteInPlace fanctl \ - --replace '--conf-file= ' \ - '--conf-file=/dev/null ' \ - --replace '/var/lib/misc' \ - '${stateDir}' - - sed -i '/dnsmasq -u/i \ - mkdir -p ${stateDir}' fanctl + --replace '@PATH@' \ + '${lib.makeSearchPath "bin" [ + gnugrep gawk coreutils bridge-utils iproute dnsmasq + iptables kmod utillinux gnused + glibc # needed for getent + ]}' ''; 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; { diff --git a/pkgs/os-specific/linux/fanctl/robustness.patch b/pkgs/os-specific/linux/fanctl/robustness.patch new file mode 100644 index 00000000000..7a70a784e3e --- /dev/null +++ b/pkgs/os-specific/linux/fanctl/robustness.patch @@ -0,0 +1,85 @@ +diff --git a/fanctl b/fanctl +index 4338b75..84cf987 100755 +--- a/fanctl ++++ b/fanctl +@@ -5,6 +5,8 @@ + # fanctl down 15 10.1.0.1 + # + ++export PATH="@PATH@" ++ + usage() + { + echo "Usage: $0 [...]" 1>&2 +@@ -23,8 +25,8 @@ run() + "$@" + } + +-state_dir="/run/ubuntu-fan" +-lconfig_dir="/var/lib/ubuntu-fan/config" ++state_dir="/run/fan-networking" ++lconfig_dir="/var/lib/fan-networking/config" + + __ip_split() + { +@@ -931,12 +933,12 @@ dhcp_reconfigure() + --strict-order \ + --bind-interfaces \ + --pid-file="$state_dir/dnsmasq-$C_bridge_state.pid" \ +- --conf-file= \ ++ --conf-file=/dev/null \ + $dhcp_flags \ + --dhcp-no-override \ + --except-interface=lo \ + --interface="$C_bridge" \ +- --dhcp-leasefile=/var/lib/misc/dnsmasq."$C_bridge_state".leases \ ++ --dhcp-leasefile=/var/lib/fan-networking/dnsmasq."$C_bridge_state".leases \ + --dhcp-authoritative \ + || $fail "$C_bridge: failed to start dnsmasq" + +@@ -1559,21 +1561,23 @@ cmd_config() + + case "$cmd" in + list|ls) +- ls -1 "$lconfig_dir" | \ +- while read config +- do +- case "$config" in +- *.conf) ;; +- *) continue ;; +- esac ++ if [ -d $lconfig_dir ]; then ++ ls -1 "$lconfig_dir" | \ ++ while read config ++ do ++ case "$config" in ++ *.conf) ;; ++ *) continue ;; ++ esac + +- config=$( echo "$config" | sed \ +- -e 's/.conf$//' \ +- -e 's/--/ /g' \ +- -e 's@-@/@g' +- ) +- echo "$config" +- done ++ config=$( echo "$config" | sed \ ++ -e 's/.conf$//' \ ++ -e 's/--/ /g' \ ++ -e 's@-@/@g' ++ ) ++ echo "$config" ++ done ++ fi + ;; + show) + cmd_decode_init +@@ -1588,6 +1592,7 @@ cmd_config() + [ -f "$uconfig" ] && cat "$uconfig" + ;; + set) ++ mkdir -p $lconfig_dir || fail "could not create config directory ($lconfig_dir)" + cmd_decode_init + if ! cmd_decode_config "config set" "$@"; then + fail "invalid config" diff --git a/pkgs/os-specific/linux/iproute/1000-ubuntu-poc-fan-driver.patch b/pkgs/os-specific/linux/iproute/1000-ubuntu-poc-fan-driver.patch new file mode 100644 index 00000000000..ca91b816000 --- /dev/null +++ b/pkgs/os-specific/linux/iproute/1000-ubuntu-poc-fan-driver.patch @@ -0,0 +1,65 @@ +Description: POC fan driver support + POC Fan driver support +Author: Jay Vosburgh + +Index: iproute2-4.1.1/include/linux/if_tunnel.h +=================================================================== +--- iproute2-4.1.1.orig/include/linux/if_tunnel.h ++++ iproute2-4.1.1/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_MAX, + }; + #define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1) +Index: iproute2-4.1.1/ip/link_iptnl.c +=================================================================== +--- iproute2-4.1.1.orig/ip/link_iptnl.c ++++ iproute2-4.1.1/ip/link_iptnl.c +@@ -66,6 +66,7 @@ static int iptunnel_parse_opt(struct lin + __u32 link = 0; + __u32 laddr = 0; + __u32 raddr = 0; ++ __u32 underlay = 0; + __u8 ttl = 0; + __u8 tos = 0; + __u8 pmtudisc = 1; +@@ -174,6 +175,9 @@ 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, "local") == 0) { + NEXT_ARG(); + if (strcmp(*argv, "any")) +@@ -318,6 +322,9 @@ get_failed: + } + } + ++ if (underlay) ++ addattr32(n, 1024, IFLA_IPTUN_FAN_UNDERLAY, underlay); ++ + return 0; + } + +@@ -349,6 +356,14 @@ static void iptunnel_print_opt(struct li + + 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_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/iproute/1001-ubuntu-poc-fan-driver-v3.patch b/pkgs/os-specific/linux/iproute/1001-ubuntu-poc-fan-driver-v3.patch new file mode 100644 index 00000000000..a940b341ea0 --- /dev/null +++ b/pkgs/os-specific/linux/iproute/1001-ubuntu-poc-fan-driver-v3.patch @@ -0,0 +1,133 @@ +Description: Fan driver support v3 + Fan driver support v3 +Author: Jay Vosburgh +Index: iproute2-4.1.1/include/linux/if_tunnel.h +=================================================================== +--- iproute2-4.1.1.orig/include/linux/if_tunnel.h ++++ iproute2-4.1.1/include/linux/if_tunnel.h +@@ -59,6 +59,7 @@ enum { + IFLA_IPTUN_ENCAP_DPORT, + + IFLA_IPTUN_FAN_UNDERLAY = 32, ++ IFLA_IPTUN_FAN_MAP = 33, + + __IFLA_IPTUN_MAX, + }; +@@ -134,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 /* _IF_TUNNEL_H_ */ +Index: iproute2-4.1.1/ip/link_iptnl.c +=================================================================== +--- iproute2-4.1.1.orig/ip/link_iptnl.c ++++ iproute2-4.1.1/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) +@@ -178,6 +214,10 @@ get_failed: + } 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")) +@@ -328,6 +368,28 @@ get_failed: + 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; ++ int p; ++ ++ fprintf(f, "fan-map "); ++ ++ rem = RTA_PAYLOAD(attr); ++ for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { ++ p = RTA_PAYLOAD(i); ++ m = RTA_DATA(i); ++ fprintf(f, "%s/%d:%s/%d ", ++ rt_addr_n2a(AF_INET, p, &m->overlay, b1, INET_ADDRSTRLEN), ++ m->overlay_prefix, ++ rt_addr_n2a(AF_INET, p, &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]; +@@ -364,6 +426,9 @@ static void iptunnel_print_opt(struct li + 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/iproute/1002-ubuntu-poc-fan-driver-vxlan.patch b/pkgs/os-specific/linux/iproute/1002-ubuntu-poc-fan-driver-vxlan.patch new file mode 100644 index 00000000000..2ddc2840bdd --- /dev/null +++ b/pkgs/os-specific/linux/iproute/1002-ubuntu-poc-fan-driver-vxlan.patch @@ -0,0 +1,177 @@ +Description: Fan driver support VXLAN (p4) + Fan driver setup support for vxlan interfaces. + +Index: iproute2-4.3.0/include/linux/if_link.h +=================================================================== +--- iproute2-4.3.0.orig/include/linux/if_link.h ++++ iproute2-4.3.0/include/linux/if_link.h +@@ -392,6 +392,7 @@ enum { + IFLA_VXLAN_GBP, + IFLA_VXLAN_REMCSUM_NOPARTIAL, + IFLA_VXLAN_COLLECT_METADATA, ++ IFLA_VXLAN_FAN_MAP = 33, + __IFLA_VXLAN_MAX + }; + #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) +Index: iproute2-4.3.0/include/linux/if_tunnel.h +=================================================================== +--- iproute2-4.3.0.orig/include/linux/if_tunnel.h ++++ iproute2-4.3.0/include/linux/if_tunnel.h +@@ -145,7 +145,7 @@ enum { + + #define IFLA_FAN_MAX (__IFLA_FAN_MAX - 1) + +-struct ip_tunnel_fan_map { ++struct ifla_fan_map { + __be32 underlay; + __be32 overlay; + __u16 underlay_prefix; +Index: iproute2-4.3.0/ip/iplink_vxlan.c +=================================================================== +--- iproute2-4.3.0.orig/ip/iplink_vxlan.c ++++ iproute2-4.3.0/ip/iplink_vxlan.c +@@ -15,7 +15,10 @@ + #include + #include + #include ++#include + #include ++#include ++#include + + #include "rt_names.h" + #include "utils.h" +@@ -43,6 +46,45 @@ static void explain(void) + print_explain(stderr); + } + ++static int fan_parse_map(int *argcp, char ***argvp, struct nlmsghdr *n) ++{ ++ inet_prefix underlay, overlay; ++ struct ifla_fan_map map; ++ struct rtattr *nest; ++ char **argv = *argvp; ++ int argc = *argcp; ++ ++ nest = addattr_nest(n, 1024, IFLA_VXLAN_FAN_MAP); ++ while (argc > 0) { ++ char *colon = strchr(*argv, ':'); ++ ++ if (!colon) { ++ PREV_ARG(); ++ 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 vxlan_parse_opt(struct link_util *lu, int argc, char **argv, + struct nlmsghdr *n) + { +@@ -201,6 +243,10 @@ static int vxlan_parse_opt(struct link_u + udp6zerocsumrx = 0; + } else if (!matches(*argv, "gbp")) { + gbp = 1; ++ } else if (!matches(*argv, "fan-map")) { ++ NEXT_ARG(); ++ if (fan_parse_map(&argc, &argv, n)) ++ invarg("invalid fan-map", *argv); + } else if (matches(*argv, "help") == 0) { + explain(); + return -1; +@@ -279,6 +325,28 @@ static int vxlan_parse_opt(struct link_u + return 0; + } + ++static void fan_print_map(FILE *f, struct rtattr *attr) ++{ ++ char b1[INET_ADDRSTRLEN], b2[INET_ADDRSTRLEN]; ++ struct ifla_fan_map *m; ++ struct rtattr *i; ++ int rem; ++ int p; ++ ++ fprintf(f, "fan-map "); ++ ++ rem = RTA_PAYLOAD(attr); ++ for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { ++ p = RTA_PAYLOAD(i); ++ m = RTA_DATA(i); ++ fprintf(f, "%s/%d:%s/%d ", ++ rt_addr_n2a(AF_INET, p, &m->overlay, b1, INET_ADDRSTRLEN), ++ m->overlay_prefix, ++ rt_addr_n2a(AF_INET, p, &m->underlay, b2, INET_ADDRSTRLEN), ++ m->underlay_prefix); ++ } ++} ++ + static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) + { + __u32 vni; +@@ -321,6 +389,9 @@ static void vxlan_print_opt(struct link_ + } + } + ++ if (tb[IFLA_VXLAN_FAN_MAP]) ++ fan_print_map(f, tb[IFLA_VXLAN_FAN_MAP]); ++ + if (tb[IFLA_VXLAN_LOCAL]) { + __be32 addr = rta_getattr_u32(tb[IFLA_VXLAN_LOCAL]); + if (addr) +Index: iproute2-4.3.0/ip/link_iptnl.c +=================================================================== +--- iproute2-4.3.0.orig/ip/link_iptnl.c ++++ iproute2-4.3.0/ip/link_iptnl.c +@@ -49,10 +49,11 @@ 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 ifla_fan_map map; + struct rtattr *nest; + char **argv = *argvp; + int argc = *argcp; +@@ -61,8 +62,10 @@ static int fan_parse_map(int *argcp, cha + while (argc > 0) { + char *colon = strchr(*argv, ':'); + +- if (!colon) ++ if (!colon) { ++ PREV_ARG(); + break; ++ } + *colon = '\0'; + + if (get_prefix(&overlay, *argv, AF_INET)) +@@ -371,7 +374,7 @@ get_failed: + static void fan_print_map(FILE *f, struct rtattr *attr) + { + char b1[INET_ADDRSTRLEN], b2[INET_ADDRSTRLEN]; +- struct ip_tunnel_fan_map *m; ++ struct ifla_fan_map *m; + struct rtattr *i; + int rem; + int p; diff --git a/pkgs/os-specific/linux/iproute/default.nix b/pkgs/os-specific/linux/iproute/default.nix index 891d39d24dd..5f328bd90c8 100644 --- a/pkgs/os-specific/linux/iproute/default.nix +++ b/pkgs/os-specific/linux/iproute/default.nix @@ -10,7 +10,13 @@ stdenv.mkDerivation rec { sha256 = "159988vv3fd78bzhisfl1dl4dd7km3vjzs2d8899a0vcvn412fzh"; }; - patches = lib.optionals enableFan [ ./ubuntu-fan.patch ]; + patches = lib.optionals enableFan [ + # These patches were pulled from: + # https://launchpad.net/ubuntu/xenial/+source/iproute2 + ./1000-ubuntu-poc-fan-driver.patch + ./1001-ubuntu-poc-fan-driver-v3.patch + ./1002-ubuntu-poc-fan-driver-vxlan.patch + ]; preConfigure = '' patchShebangs ./configure diff --git a/pkgs/os-specific/linux/iproute/ubuntu-fan.patch b/pkgs/os-specific/linux/iproute/ubuntu-fan.patch deleted file mode 100644 index e55425c2ce6..00000000000 --- a/pkgs/os-specific/linux/iproute/ubuntu-fan.patch +++ /dev/null @@ -1,164 +0,0 @@ -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 a8fb1598af7..a23ee7823a6 100644 --- a/pkgs/os-specific/linux/kernel/patches.nix +++ b/pkgs/os-specific/linux/kernel/patches.nix @@ -71,14 +71,9 @@ rec { patch = ./mips-ext3-n32.patch; }; - ubuntu_fan = + ubuntu_fan_4_4 = { name = "ubuntu-fan"; - patch = ./ubuntu-fan-3.patch; - }; - - ubuntu_fan_4 = - { name = "ubuntu-fan"; - patch = ./ubuntu-fan-4.patch; + patch = ./ubuntu-fan-4.4.patch; }; ubuntu_unprivileged_overlayfs = diff --git a/pkgs/os-specific/linux/kernel/ubuntu-fan-3.patch b/pkgs/os-specific/linux/kernel/ubuntu-fan-3.patch deleted file mode 100644 index c80950d0614..00000000000 --- a/pkgs/os-specific/linux/kernel/ubuntu-fan-3.patch +++ /dev/null @@ -1,616 +0,0 @@ -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.4.patch b/pkgs/os-specific/linux/kernel/ubuntu-fan-4.4.patch new file mode 100644 index 00000000000..39150ad790d --- /dev/null +++ b/pkgs/os-specific/linux/kernel/ubuntu-fan-4.4.patch @@ -0,0 +1,1240 @@ +From e64058be3b97c5bd3e034fc4ece21e306ef6f90b Mon Sep 17 00:00:00 2001 +From: Jay Vosburgh +Date: Wed, 1 Apr 2015 16:11:09 -0700 +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 +Signed-off-by: Tim Gardner + +Conflicts: + include/net/ip_tunnels.h +--- + include/net/ip_tunnels.h | 15 ++++ + include/uapi/linux/if_tunnel.h | 20 +++++ + net/ipv4/ip_tunnel.c | 7 +- + net/ipv4/ipip.c | 186 +++++++++++++++++++++++++++++++++++++++-- + 4 files changed, 222 insertions(+), 6 deletions(-) + +diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h +index 62a750a..47fec59 100644 +--- a/include/net/ip_tunnels.h ++++ b/include/net/ip_tunnels.h +@@ -91,6 +91,19 @@ struct ip_tunnel_dst { + }; + + struct metadata_dst; ++/* 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 __rcu *map;*/ ++ u32 map[FAN_OVERLAY_CNT]; ++}; + + struct ip_tunnel { + struct ip_tunnel __rcu *next; +@@ -123,6 +136,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; + bool collect_md; +@@ -143,6 +157,7 @@ struct ip_tunnel { + #define TUNNEL_VXLAN_OPT __cpu_to_be16(0x1000) + + #define TUNNEL_OPTIONS_PRESENT (TUNNEL_GENEVE_OPT | TUNNEL_VXLAN_OPT) ++#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 af4de90..85a3e4b 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_MAP = 33, ++ + __IFLA_IPTUN_MAX, + }; + #define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1) +@@ -132,4 +136,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 cbb51f3..7a6174b 100644 +--- a/net/ipv4/ip_tunnel.c ++++ b/net/ipv4/ip_tunnel.c +@@ -1110,6 +1110,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) + { +@@ -1119,7 +1124,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 a09fb0d..56e8984 100644 +--- a/net/ipv4/ipip.c ++++ b/net/ipv4/ipip.c +@@ -107,6 +107,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -208,6 +209,40 @@ 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 ++ * 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 int ipip_build_fan_iphdr(struct ip_tunnel *tunnel, struct sk_buff *skb, struct iphdr *iph) ++{ ++ unsigned int overlay; ++ u32 daddr, underlay; ++ ++ daddr = ntohl(ip_hdr(skb)->daddr); ++ 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; ++} ++ + /* + * This function assumes it is being called from dev_queue_xmit() + * and that skb is filled properly by that function. +@@ -215,7 +250,8 @@ drop: + 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 +260,14 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) + if (IS_ERR(skb)) + goto out; + ++ if (ipip_tunnel_is_fan(tunnel)) { ++ if (ipip_build_fan_iphdr(tunnel, skb, &fiph)) ++ goto tx_error; ++ tiph = &fiph; ++ } else { ++ tiph = &tunnel->parms.iph; ++ } ++ + skb_set_inner_ipproto(skb, IPPROTO_IPIP); + + ip_tunnel_xmit(skb, dev, tiph, tiph->protocol); +@@ -375,21 +419,88 @@ 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) ++{ ++ struct ip_tunnel_fan_map *map; ++ struct nlattr *attr; ++ int rem, rv; ++ ++ if (!data[IFLA_IPTUN_FAN_MAP]) ++ return 0; ++ ++ if (parms->iph.daddr) ++ return -EINVAL; ++ ++ 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; ++} ++ + 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); + } + +@@ -398,16 +509,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)) +@@ -439,6 +554,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_MAP */ ++ nla_total_size(sizeof(struct ip_tunnel_fan_map)) * 256 + + 0; + } + +@@ -466,6 +583,29 @@ static int ipip_fill_info(struct sk_buff *skb, const struct net_device *dev) + tunnel->encap.flags)) + goto nla_put_failure; + ++ 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; + + nla_put_failure: +@@ -483,6 +623,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_MAP] = { .type = NLA_NESTED }, + }; + + static struct rtnl_link_ops ipip_link_ops __read_mostly = { +@@ -523,6 +666,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 = 3; ++ ++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; +@@ -541,9 +701,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: +@@ -553,6 +726,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.7.4 + +From 14aba409d044e3a314c09c650e1c42de699700b8 Mon Sep 17 00:00:00 2001 +From: Jay Vosburgh +Date: Wed, 11 Nov 2015 13:04:50 +0000 +Subject: [PATCH] UBUNTU: SAUCE: fan: add VXLAN implementation + +Generify the fan mapping support and utilise that to implement fan +mappings over vxlan transport. + +Expose the existance of this functionality (when the module is loaded) +via an additional sysctl marker. + +Signed-off-by: Jay Vosburgh +[apw@canonical.com: added feature marker for fan over vxlan.] +Signed-off-by: Andy Whitcroft +--- + drivers/net/vxlan.c | 245 +++++++++++++++++++++++++++++++++++++++++ + include/net/ip_tunnels.h | 19 +++- + include/net/vxlan.h | 2 + + include/uapi/linux/if_link.h | 1 + + include/uapi/linux/if_tunnel.h | 2 +- + net/ipv4/ip_tunnel.c | 7 +- + net/ipv4/ipip.c | 242 +++++++++++++++++++++++++++++++--------- + 7 files changed, 453 insertions(+), 65 deletions(-) + +diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c +index 405a7b6..a17cfd0 100644 +--- a/drivers/net/vxlan.c ++++ b/drivers/net/vxlan.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -106,6 +107,167 @@ static inline bool vxlan_collect_metadata(struct vxlan_sock *vs) + ip_tunnel_collect_metadata(); + } + ++static struct ip_fan_map *vxlan_fan_find_map(struct vxlan_dev *vxlan, __be32 daddr) ++{ ++ struct ip_fan_map *fan_map; ++ ++ rcu_read_lock(); ++ list_for_each_entry_rcu(fan_map, &vxlan->fan.fan_maps, list) { ++ if (fan_map->overlay == ++ (daddr & inet_make_mask(fan_map->overlay_prefix))) { ++ rcu_read_unlock(); ++ return fan_map; ++ } ++ } ++ rcu_read_unlock(); ++ ++ return NULL; ++} ++ ++static void vxlan_fan_flush_map(struct vxlan_dev *vxlan) ++{ ++ struct ip_fan_map *fan_map; ++ ++ list_for_each_entry_rcu(fan_map, &vxlan->fan.fan_maps, list) { ++ list_del_rcu(&fan_map->list); ++ kfree_rcu(fan_map, rcu); ++ } ++} ++ ++static int vxlan_fan_del_map(struct vxlan_dev *vxlan, __be32 overlay) ++{ ++ struct ip_fan_map *fan_map; ++ ++ fan_map = vxlan_fan_find_map(vxlan, overlay); ++ if (!fan_map) ++ return -ENOENT; ++ ++ list_del_rcu(&fan_map->list); ++ kfree_rcu(fan_map, rcu); ++ ++ return 0; ++} ++ ++static int vxlan_fan_add_map(struct vxlan_dev *vxlan, struct ifla_fan_map *map) ++{ ++ __be32 overlay_mask, underlay_mask; ++ struct ip_fan_map *fan_map; ++ ++ overlay_mask = inet_make_mask(map->overlay_prefix); ++ underlay_mask = inet_make_mask(map->underlay_prefix); ++ ++ netdev_dbg(vxlan->dev, "vfam: map: o %x/%d u %x/%d om %x um %x\n", ++ map->overlay, map->overlay_prefix, ++ map->underlay, map->underlay_prefix, ++ overlay_mask, underlay_mask); ++ ++ if ((map->overlay & ~overlay_mask) || (map->underlay & ~underlay_mask)) ++ return -EINVAL; ++ ++ if (!(map->overlay & overlay_mask) && (map->underlay & underlay_mask)) ++ return -EINVAL; ++ ++ /* Special case: overlay 0 and underlay 0: flush all mappings */ ++ if (!map->overlay && !map->underlay) { ++ vxlan_fan_flush_map(vxlan); ++ return 0; ++ } ++ ++ /* Special case: overlay set and underlay 0: clear map for overlay */ ++ if (!map->underlay) ++ return vxlan_fan_del_map(vxlan, map->overlay); ++ ++ if (vxlan_fan_find_map(vxlan, map->overlay)) ++ return -EEXIST; ++ ++ fan_map = kmalloc(sizeof(*fan_map), GFP_KERNEL); ++ fan_map->underlay = map->underlay; ++ fan_map->overlay = map->overlay; ++ fan_map->underlay_prefix = map->underlay_prefix; ++ fan_map->overlay_mask = ntohl(overlay_mask); ++ fan_map->overlay_prefix = map->overlay_prefix; ++ ++ list_add_tail_rcu(&fan_map->list, &vxlan->fan.fan_maps); ++ ++ return 0; ++} ++ ++static int vxlan_parse_fan_map(struct nlattr *data[], struct vxlan_dev *vxlan) ++{ ++ struct ifla_fan_map *map; ++ struct nlattr *attr; ++ int rem, rv; ++ ++ nla_for_each_nested(attr, data[IFLA_IPTUN_FAN_MAP], rem) { ++ map = nla_data(attr); ++ rv = vxlan_fan_add_map(vxlan, map); ++ if (rv) ++ return rv; ++ } ++ ++ return 0; ++} ++ ++static int vxlan_fan_build_rdst(struct vxlan_dev *vxlan, struct sk_buff *skb, ++ struct vxlan_rdst *fan_rdst) ++{ ++ struct ip_fan_map *f_map; ++ union vxlan_addr *va; ++ u32 daddr, underlay; ++ struct arphdr *arp; ++ void *arp_ptr; ++ struct ethhdr *eth; ++ struct iphdr *iph; ++ ++ eth = eth_hdr(skb); ++ switch (eth->h_proto) { ++ case htons(ETH_P_IP): ++ iph = ip_hdr(skb); ++ if (!iph) ++ return -EINVAL; ++ daddr = iph->daddr; ++ break; ++ case htons(ETH_P_ARP): ++ arp = arp_hdr(skb); ++ if (!arp) ++ return -EINVAL; ++ arp_ptr = arp + 1; ++ netdev_dbg(vxlan->dev, ++ "vfbr: arp sha %pM sip %pI4 tha %pM tip %pI4\n", ++ arp_ptr, arp_ptr + skb->dev->addr_len, ++ arp_ptr + skb->dev->addr_len + 4, ++ arp_ptr + (skb->dev->addr_len * 2) + 4); ++ arp_ptr += (skb->dev->addr_len * 2) + 4; ++ memcpy(&daddr, arp_ptr, 4); ++ break; ++ default: ++ netdev_dbg(vxlan->dev, "vfbr: unknown eth p %x\n", eth->h_proto); ++ return -EINVAL; ++ } ++ ++ f_map = vxlan_fan_find_map(vxlan, daddr); ++ if (!f_map) ++ return -EINVAL; ++ ++ daddr = ntohl(daddr); ++ underlay = ntohl(f_map->underlay); ++ if (!underlay) ++ return -EINVAL; ++ ++ memset(fan_rdst, 0, sizeof(*fan_rdst)); ++ va = &fan_rdst->remote_ip; ++ va->sa.sa_family = AF_INET; ++ fan_rdst->remote_vni = vxlan->default_dst.remote_vni; ++ va->sin.sin_addr.s_addr = htonl(underlay | ++ ((daddr & ~f_map->overlay_mask) >> ++ (32 - f_map->overlay_prefix - ++ (32 - f_map->underlay_prefix)))); ++ netdev_dbg(vxlan->dev, "vfbr: daddr %x ul %x dst %x\n", ++ daddr, underlay, va->sin.sin_addr.s_addr); ++ ++ return 0; ++} ++ + #if IS_ENABLED(CONFIG_IPV6) + static inline + bool vxlan_addr_equal(const union vxlan_addr *a, const union vxlan_addr *b) +@@ -2029,6 +2191,13 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, + goto rt_tx_error; + } + ++ if (fan_has_map(&vxlan->fan) && rt->rt_flags & RTCF_LOCAL) { ++ netdev_dbg(dev, "discard fan to localhost %pI4\n", ++ &dst->sin.sin_addr.s_addr); ++ ip_rt_put(rt); ++ goto tx_free; ++ } ++ + /* Bypass encapsulation if the destination is local */ + if (rt->rt_flags & RTCF_LOCAL && + !(rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))) { +@@ -2169,6 +2338,20 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) + return NETDEV_TX_OK; + } + ++ if (fan_has_map(&vxlan->fan)) { ++ struct vxlan_rdst fan_rdst; ++ ++ netdev_dbg(vxlan->dev, "vxlan_xmit p %x d %pM\n", ++ eth->h_proto, eth->h_dest); ++ if (vxlan_fan_build_rdst(vxlan, skb, &fan_rdst)) { ++ dev->stats.tx_dropped++; ++ kfree_skb(skb); ++ return NETDEV_TX_OK; ++ } ++ vxlan_xmit_one(skb, dev, &fan_rdst, 0); ++ return NETDEV_TX_OK; ++ } ++ + f = vxlan_find_mac(vxlan, eth->h_dest); + did_rsc = false; + +@@ -2532,6 +2715,8 @@ static void vxlan_setup(struct net_device *dev) + + for (h = 0; h < FDB_HASH_SIZE; ++h) + INIT_HLIST_HEAD(&vxlan->fdb_head[h]); ++ ++ INIT_LIST_HEAD(&vxlan->fan.fan_maps); + } + + static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = { +@@ -2881,6 +3066,7 @@ EXPORT_SYMBOL_GPL(vxlan_dev_create); + static int vxlan_newlink(struct net *src_net, struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[]) + { ++ struct vxlan_dev *vxlan = netdev_priv(dev); + struct vxlan_config conf; + int err; + +@@ -2899,6 +3085,12 @@ static int vxlan_newlink(struct net *src_net, struct net_device *dev, + conf.remote_ip.sa.sa_family = AF_INET6; + } + ++ if (data[IFLA_VXLAN_FAN_MAP]) { ++ err = vxlan_parse_fan_map(data, vxlan); ++ if (err) ++ return err; ++ } ++ + if (data[IFLA_VXLAN_LOCAL]) { + conf.saddr.sin.sin_addr.s_addr = nla_get_in_addr(data[IFLA_VXLAN_LOCAL]); + conf.saddr.sa.sa_family = AF_INET; +@@ -3037,6 +3229,7 @@ static size_t vxlan_get_size(const struct net_device *dev) + nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_UDP_ZERO_CSUM6_RX */ + nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_REMCSUM_TX */ + nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_REMCSUM_RX */ ++ nla_total_size(sizeof(struct ip_fan_map) * 256) + + 0; + } + +@@ -3083,6 +3276,26 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev) + } + } + ++ if (fan_has_map(&vxlan->fan)) { ++ struct nlattr *fan_nest; ++ struct ip_fan_map *fan_map; ++ ++ fan_nest = nla_nest_start(skb, IFLA_VXLAN_FAN_MAP); ++ if (!fan_nest) ++ goto nla_put_failure; ++ list_for_each_entry_rcu(fan_map, &vxlan->fan.fan_maps, list) { ++ struct ifla_fan_map map; ++ ++ map.underlay = fan_map->underlay; ++ map.underlay_prefix = fan_map->underlay_prefix; ++ map.overlay = fan_map->overlay; ++ map.overlay_prefix = fan_map->overlay_prefix; ++ if (nla_put(skb, IFLA_FAN_MAPPING, sizeof(map), &map)) ++ goto nla_put_failure; ++ } ++ nla_nest_end(skb, fan_nest); ++ } ++ + if (nla_put_u8(skb, IFLA_VXLAN_TTL, vxlan->cfg.ttl) || + nla_put_u8(skb, IFLA_VXLAN_TOS, vxlan->cfg.tos) || + nla_put_u8(skb, IFLA_VXLAN_LEARNING, +@@ -3201,6 +3414,22 @@ static __net_init int vxlan_init_net(struct net *net) + return 0; + } + ++#ifdef CONFIG_SYSCTL ++static struct ctl_table_header *vxlan_fan_header; ++static unsigned int vxlan_fan_version = 4; ++ ++static struct ctl_table vxlan_fan_sysctls[] = { ++ { ++ .procname = "vxlan", ++ .data = &vxlan_fan_version, ++ .maxlen = sizeof(vxlan_fan_version), ++ .mode = 0444, ++ .proc_handler = proc_dointvec, ++ }, ++ {}, ++}; ++#endif /* CONFIG_SYSCTL */ ++ + static void __net_exit vxlan_exit_net(struct net *net) + { + struct vxlan_net *vn = net_generic(net, vxlan_net_id); +@@ -3256,7 +3485,20 @@ static int __init vxlan_init_module(void) + if (rc) + goto out3; + ++#ifdef CONFIG_SYSCTL ++ vxlan_fan_header = register_net_sysctl(&init_net, "net/fan", ++ vxlan_fan_sysctls); ++ if (!vxlan_fan_header) { ++ rc = -ENOMEM; ++ goto sysctl_failed; ++ } ++#endif /* CONFIG_SYSCTL */ ++ + return 0; ++#ifdef CONFIG_SYSCTL ++sysctl_failed: ++ rtnl_link_unregister(&vxlan_link_ops); ++#endif /* CONFIG_SYSCTL */ + out3: + unregister_netdevice_notifier(&vxlan_notifier_block); + out2: +@@ -3269,6 +3511,9 @@ late_initcall(vxlan_init_module); + + static void __exit vxlan_cleanup_module(void) + { ++#ifdef CONFIG_SYSCTL ++ unregister_net_sysctl_table(vxlan_fan_header); ++#endif /* CONFIG_SYSCTL */ + rtnl_link_unregister(&vxlan_link_ops); + unregister_netdevice_notifier(&vxlan_notifier_block); + destroy_workqueue(vxlan_wq); +diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h +index 47fec59..28a38e5 100644 +--- a/include/net/ip_tunnels.h ++++ b/include/net/ip_tunnels.h +@@ -100,9 +100,18 @@ struct metadata_dst; + */ + #define FAN_OVERLAY_CNT 256 + ++struct ip_fan_map { ++ __be32 underlay; ++ __be32 overlay; ++ u16 underlay_prefix; ++ u16 overlay_prefix; ++ u32 overlay_mask; ++ struct list_head list; ++ struct rcu_head rcu; ++}; ++ + struct ip_tunnel_fan { +-/* u32 __rcu *map;*/ +- u32 map[FAN_OVERLAY_CNT]; ++ struct list_head fan_maps; + }; + + struct ip_tunnel { +@@ -157,7 +166,11 @@ struct ip_tunnel { + #define TUNNEL_VXLAN_OPT __cpu_to_be16(0x1000) + + #define TUNNEL_OPTIONS_PRESENT (TUNNEL_GENEVE_OPT | TUNNEL_VXLAN_OPT) +-#define TUNNEL_FAN __cpu_to_be16(0x4000) ++ ++static inline int fan_has_map(const struct ip_tunnel_fan *fan) ++{ ++ return !list_empty(&fan->fan_maps); ++} + + struct tnl_ptk_info { + __be16 flags; +diff --git a/include/net/vxlan.h b/include/net/vxlan.h +index e289ada..542f421 100644 +--- a/include/net/vxlan.h ++++ b/include/net/vxlan.h +@@ -161,6 +161,8 @@ struct vxlan_dev { + struct vxlan_rdst default_dst; /* default destination */ + u32 flags; /* VXLAN_F_* in vxlan.h */ + ++ struct ip_tunnel_fan fan; ++ + struct timer_list age_timer; + spinlock_t hash_lock; + unsigned int addrcnt; +diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h +index 5ad5737..6cde3bf 100644 +--- a/include/uapi/linux/if_link.h ++++ b/include/uapi/linux/if_link.h +@@ -443,6 +443,7 @@ enum { + IFLA_VXLAN_GBP, + IFLA_VXLAN_REMCSUM_NOPARTIAL, + IFLA_VXLAN_COLLECT_METADATA, ++ IFLA_VXLAN_FAN_MAP = 33, + __IFLA_VXLAN_MAX + }; + #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) +diff --git a/include/uapi/linux/if_tunnel.h b/include/uapi/linux/if_tunnel.h +index 85a3e4b..d36b150 100644 +--- a/include/uapi/linux/if_tunnel.h ++++ b/include/uapi/linux/if_tunnel.h +@@ -145,7 +145,7 @@ enum { + + #define IFLA_FAN_MAX (__IFLA_FAN_MAX - 1) + +-struct ip_tunnel_fan_map { ++struct ifla_fan_map { + __be32 underlay; + __be32 overlay; + __u16 underlay_prefix; +diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c +index 7a6174b..c821bf1 100644 +--- a/net/ipv4/ip_tunnel.c ++++ b/net/ipv4/ip_tunnel.c +@@ -1110,11 +1110,6 @@ 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) + { +@@ -1124,7 +1119,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 ip_tunnel_is_fan(tunnel) ? 0 : -EINVAL; ++ return fan_has_map(&tunnel->fan) ? 0 : -EINVAL; + + t = ip_tunnel_find(itn, p, dev->type); + +diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c +index 56e8984..3877b0e 100644 +--- a/net/ipv4/ipip.c ++++ b/net/ipv4/ipip.c +@@ -108,6 +108,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -209,37 +210,144 @@ drop: + return 0; + } + +-static int ipip_tunnel_is_fan(struct ip_tunnel *tunnel) ++static struct ip_fan_map *ipip_fan_find_map(struct ip_tunnel *t, __be32 daddr) + { +- return tunnel->parms.i_flags & TUNNEL_FAN; ++ struct ip_fan_map *fan_map; ++ ++ rcu_read_lock(); ++ list_for_each_entry_rcu(fan_map, &t->fan.fan_maps, list) { ++ if (fan_map->overlay == ++ (daddr & inet_make_mask(fan_map->overlay_prefix))) { ++ rcu_read_unlock(); ++ return fan_map; ++ } ++ } ++ rcu_read_unlock(); ++ ++ return NULL; + } + +-/* +- * 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. ++/* Determine fan tunnel endpoint to send packet to, based on the inner IP ++ * address. ++ * ++ * Given a /8 overlay and /16 underlay, 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/16 with an overlay of 99.0.0.0/8 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 subnet 99.6.7.0/24. This transformation is ++ * described in detail further below. ++ * ++ * Using netmasks for the overlay and underlay other than /8 and /16, as ++ * shown above, can yield larger (or smaller) overlay subnets, with the ++ * trade-off of allowing fewer (or more) underlay hosts to participate. ++ * ++ * The size of each overlay network subnet is defined by the total of the ++ * network mask of the overlay plus the size of host portion of the ++ * underlay network. In the above example, /8 + /16 = /24. ++ * ++ * E.g., consider underlay host 10.99.238.5/20 and overlay 99.0.0.0/8. In ++ * this case, the network portion of the underlay is 10.99.224.0/20, and ++ * the host portion is 0.0.14.5 (12 bits). To determine the overlay ++ * network subnet, the 12 bits of host portion are left shifted 12 bits ++ * (/20 - /8) and ORed with the overlay subnet prefix. This yields an ++ * overlay subnet of 99.224.80/20, composed of 8 bits overlay, followed by ++ * 12 bits underlay. This yields 12 bits in the overlay network portion, ++ * allowing for 4094 addresses in each overlay network subnet. The ++ * trade-off is that fewer hosts may participate in the underlay network, ++ * as its host address size has shrunk from 16 bits (65534 addresses) in ++ * the first example to 12 bits (4094 addresses) here. ++ * ++ * For fewer hosts per overlay subnet (permitting a larger number of ++ * underlay hosts to participate), the underlay netmask may be made ++ * smaller. ++ * ++ * E.g., underlay host 10.111.1.2/12 (network 10.96.0.0/12, host portion ++ * is 0.15.1.2, 20 bits) with an overlay of 33.0.0.0/8 would left shift ++ * the 20 bits of host by 4 (so that it's highest order bit is adjacent to ++ * the lowest order bit of the /8 overlay). This yields an overlay subnet ++ * of 33.240.16.32/28 (8 bits overlay, 20 bits from the host portion of ++ * the underlay). This provides more addresses for the underlay network ++ * (approximately 2^20), but each host's segment of the overlay provides ++ * only 4 bits of addresses (14 usable). ++ * ++ * It is also possible to adjust the overlay subnet. ++ * ++ * For an overlay of 240.0.0.0/5 and underlay of 10.88.0.0/20, consider ++ * underlay host 10.88.129.2; the 12 bits of host, 0.0.1.2, are left ++ * shifted 15 bits (/20 - /5), yielding an overlay network of ++ * 240.129.0.0/17. An underlay host of 10.88.244.215 would yield an ++ * overlay network of 242.107.128.0/17. ++ * ++ * For an overlay of 100.64.0.0/10 and underlay of 10.224.220.0/24, for ++ * underlay host 10.224.220.10, the underlay host portion (.10) is left ++ * shifted 14 bits, yielding an overlay network subnet of 100.66.128.0/18. ++ * This would permit 254 addresses on the underlay, with each overlay ++ * segment providing approximately 2^14 - 2 addresses (16382). ++ * ++ * For packets being encapsulated, the overlay network destination IP ++ * address is deconstructed into its overlay and underlay-derived ++ * portions. The underlay portion (determined by the overlay mask and ++ * overlay subnet mask) is right shifted according to the size of the ++ * underlay network mask. This value is then ORed with the network ++ * portion of the underlay network to produce the underlay network ++ * destination for the encapsulated datagram. ++ * ++ * For example, using the initial example of underlay 10.88.3.4/16 and ++ * overlay 99.0.0.0/8, with underlay host 10.88.3.4/16 providing overlay ++ * subnet 99.3.4.0/24 with specfic host 99.3.4.5. A datagram from ++ * 99.3.4.5 to 99.6.7.8 would first have the underlay host derived portion ++ * of the address extracted. This is a number of bits equal to underlay ++ * network host portion. In the destination address, the highest order of ++ * these bits is one bit lower than the lowest order bit from the overlay ++ * network mask. ++ * ++ * Using the sample value, 99.6.7.8, the overlay mask is /8, and the ++ * underlay mask is /16 (leaving 16 bits for the host portion). The bits ++ * to be shifted are the middle two octets, 0.6.7.0, as this is 99.6.7.8 ++ * ANDed with the mask 0x00ffff00 (which is 16 bits, the highest order of ++ * which is 1 bit lower than the lowest order overlay address bit). + * +- * 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. ++ * These octets, 0.6.7.0, are then right shifted 8 bits, yielding 0.0.6.7. ++ * This value is then ORed with the underlay network portion, ++ * 10.88.0.0/16, providing 10.88.6.7 as the final underlay destination for ++ * the encapuslated datagram. ++ * ++ * Another transform using the final example: overlay 100.64.0.0/10 and ++ * underlay 10.224.220.0/24. Consider overlay address 100.66.128.1 ++ * sending a datagram to 100.66.200.5. In this case, 8 bits (the host ++ * portion size of 10.224.220.0/24) beginning after the 100.64/10 overlay ++ * prefix are masked off, yielding 0.2.192.0. This is right shifted 14 ++ * (32 - 10 - (32 - 24), i.e., the number of bits between the overlay ++ * network portion and the underlay host portion) bits, yielding 0.0.0.11. ++ * This is ORed with the underlay network portion, 10.224.220.0/24, giving ++ * the underlay destination of 10.224.220.11 for overlay destination ++ * 100.66.200.5. + */ + static int ipip_build_fan_iphdr(struct ip_tunnel *tunnel, struct sk_buff *skb, struct iphdr *iph) + { +- unsigned int overlay; ++ struct ip_fan_map *f_map; + u32 daddr, underlay; + ++ f_map = ipip_fan_find_map(tunnel, ip_hdr(skb)->daddr); ++ if (!f_map) ++ return -ENOENT; ++ + daddr = ntohl(ip_hdr(skb)->daddr); +- overlay = daddr >> 24; +- underlay = tunnel->fan.map[overlay]; ++ underlay = ntohl(f_map->underlay); + if (!underlay) + return -EINVAL; + + *iph = tunnel->parms.iph; +- iph->daddr = htonl(underlay | ((daddr >> 8) & 0x0000ffff)); ++ iph->daddr = htonl(underlay | ++ ((daddr & ~f_map->overlay_mask) >> ++ (32 - f_map->overlay_prefix - ++ (32 - f_map->underlay_prefix)))); + return 0; + } + +@@ -260,7 +368,7 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) + if (IS_ERR(skb)) + goto out; + +- if (ipip_tunnel_is_fan(tunnel)) { ++ if (fan_has_map(&tunnel->fan)) { + if (ipip_build_fan_iphdr(tunnel, skb, &fiph)) + goto tx_error; + tiph = &fiph; +@@ -325,6 +433,8 @@ static const struct net_device_ops ipip_netdev_ops = { + + static void ipip_tunnel_setup(struct net_device *dev) + { ++ struct ip_tunnel *t = netdev_priv(dev); ++ + dev->netdev_ops = &ipip_netdev_ops; + + dev->type = ARPHRD_TUNNEL; +@@ -336,6 +446,7 @@ static void ipip_tunnel_setup(struct net_device *dev) + dev->features |= IPIP_FEATURES; + dev->hw_features |= IPIP_FEATURES; + ip_tunnel_setup(dev, ipip_net_id); ++ INIT_LIST_HEAD(&t->fan.fan_maps); + } + + static int ipip_tunnel_init(struct net_device *dev) +@@ -419,41 +530,65 @@ static bool ipip_netlink_encap_parms(struct nlattr *data[], + return ret; + } + +-static void ipip_fan_free_map(struct ip_tunnel *t) ++static void ipip_fan_flush_map(struct ip_tunnel *t) + { +- memset(&t->fan.map, 0, sizeof(t->fan.map)); ++ struct ip_fan_map *fan_map; ++ ++ list_for_each_entry_rcu(fan_map, &t->fan.fan_maps, list) { ++ list_del_rcu(&fan_map->list); ++ kfree_rcu(fan_map, rcu); ++ } + } + +-static int ipip_fan_set_map(struct ip_tunnel *t, struct ip_tunnel_fan_map *map) ++static int ipip_fan_del_map(struct ip_tunnel *t, __be32 overlay) + { +- u32 overlay, overlay_mask, underlay, underlay_mask; ++ struct ip_fan_map *fan_map; + +- if ((map->underlay_prefix && map->underlay_prefix != 16) || +- (map->overlay_prefix && map->overlay_prefix != 8)) +- return -EINVAL; ++ fan_map = ipip_fan_find_map(t, overlay); ++ if (!fan_map) ++ return -ENOENT; ++ ++ list_del_rcu(&fan_map->list); ++ kfree_rcu(fan_map, rcu); + +- overlay = ntohl(map->overlay); +- overlay_mask = ntohl(inet_make_mask(map->overlay_prefix)); ++ return 0; ++} + +- underlay = ntohl(map->underlay); +- underlay_mask = ntohl(inet_make_mask(map->underlay_prefix)); ++static int ipip_fan_add_map(struct ip_tunnel *t, struct ifla_fan_map *map) ++{ ++ __be32 overlay_mask, underlay_mask; ++ struct ip_fan_map *fan_map; + +- if ((overlay & ~overlay_mask) || (underlay & ~underlay_mask)) +- return -EINVAL; ++ overlay_mask = inet_make_mask(map->overlay_prefix); ++ underlay_mask = inet_make_mask(map->underlay_prefix); + +- if (!(overlay & overlay_mask) && (underlay & underlay_mask)) ++ if ((map->overlay & ~overlay_mask) || (map->underlay & ~underlay_mask)) + return -EINVAL; + +- t->parms.i_flags |= TUNNEL_FAN; ++ if (!(map->overlay & overlay_mask) && (map->underlay & underlay_mask)) ++ return -EINVAL; + +- /* Special case: overlay 0 and underlay 0 clears all mappings */ +- if (!overlay && !underlay) { +- ipip_fan_free_map(t); ++ /* Special case: overlay 0 and underlay 0: flush all mappings */ ++ if (!map->overlay && !map->underlay) { ++ ipip_fan_flush_map(t); + return 0; + } ++ ++ /* Special case: overlay set and underlay 0: clear map for overlay */ ++ if (!map->underlay) ++ return ipip_fan_del_map(t, map->overlay); ++ ++ if (ipip_fan_find_map(t, map->overlay)) ++ return -EEXIST; ++ ++ fan_map = kmalloc(sizeof(*fan_map), GFP_KERNEL); ++ fan_map->underlay = map->underlay; ++ fan_map->overlay = map->overlay; ++ fan_map->underlay_prefix = map->underlay_prefix; ++ fan_map->overlay_mask = ntohl(overlay_mask); ++ fan_map->overlay_prefix = map->overlay_prefix; + +- overlay >>= (32 - map->overlay_prefix); +- t->fan.map[overlay] = underlay; ++ list_add_tail_rcu(&fan_map->list, &t->fan.fan_maps); + + return 0; + } +@@ -462,7 +597,7 @@ static int ipip_fan_set_map(struct ip_tunnel *t, struct ip_tunnel_fan_map *map) + static int ipip_netlink_fan(struct nlattr *data[], struct ip_tunnel *t, + struct ip_tunnel_parm *parms) + { +- struct ip_tunnel_fan_map *map; ++ struct ifla_fan_map *map; + struct nlattr *attr; + int rem, rv; + +@@ -474,7 +609,7 @@ static int ipip_netlink_fan(struct nlattr *data[], struct ip_tunnel *t, + + nla_for_each_nested(attr, data[IFLA_IPTUN_FAN_MAP], rem) { + map = nla_data(attr); +- rv = ipip_fan_set_map(t, map); ++ rv = ipip_fan_add_map(t, map); + if (rv) + return rv; + } +@@ -555,7 +690,7 @@ static size_t ipip_get_size(const struct net_device *dev) + /* IFLA_IPTUN_ENCAP_DPORT */ + nla_total_size(2) + + /* IFLA_IPTUN_FAN_MAP */ +- nla_total_size(sizeof(struct ip_tunnel_fan_map)) * 256 + ++ nla_total_size(sizeof(struct ifla_fan_map)) * 256 + + 0; + } + +@@ -583,25 +718,22 @@ static int ipip_fill_info(struct sk_buff *skb, const struct net_device *dev) + tunnel->encap.flags)) + goto nla_put_failure; + +- if (tunnel->parms.i_flags & TUNNEL_FAN) { ++ if (fan_has_map(&tunnel->fan)) { + struct nlattr *fan_nest; +- int i; ++ struct ip_fan_map *fan_map; + + 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; +- } ++ list_for_each_entry_rcu(fan_map, &tunnel->fan.fan_maps, list) { ++ struct ifla_fan_map map; ++ ++ map.underlay = fan_map->underlay; ++ map.underlay_prefix = fan_map->underlay_prefix; ++ map.overlay = fan_map->overlay; ++ map.overlay_prefix = fan_map->overlay_prefix; ++ if (nla_put(skb, IFLA_FAN_MAPPING, sizeof(map), &map)) ++ goto nla_put_failure; + } + nla_nest_end(skb, fan_nest); + } +-- +2.7.4 + diff --git a/pkgs/os-specific/linux/kernel/ubuntu-fan-4.patch b/pkgs/os-specific/linux/kernel/ubuntu-fan-4.patch deleted file mode 100644 index 0050af6c252..00000000000 --- a/pkgs/os-specific/linux/kernel/ubuntu-fan-4.patch +++ /dev/null @@ -1,616 +0,0 @@ -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 - -- cgit 1.4.1