Merge pull request #14566 from cstrahan/ubuntu-fan-update

fan-networking: updated patches from Ubuntu

+22 -24
pkgs/os-specific/linux/fanctl/default.nix
···
-
{ 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; {
+85
pkgs/os-specific/linux/fanctl/robustness.patch
···
+
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 <cmd> [<options>...]" 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"
+65
pkgs/os-specific/linux/iproute/1000-ubuntu-poc-fan-driver.patch
···
+
Description: POC fan driver support
+
POC Fan driver support
+
Author: Jay Vosburgh <jay.vosburgh@canonical.com>
+
+
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);
+133
pkgs/os-specific/linux/iproute/1001-ubuntu-poc-fan-driver-v3.patch
···
+
Description: Fan driver support v3
+
Fan driver support v3
+
Author: Jay Vosburgh <jay.vosburgh@canonical.com>
+
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);
+177
pkgs/os-specific/linux/iproute/1002-ubuntu-poc-fan-driver-vxlan.patch
···
+
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 <net/if.h>
+
#include <linux/ip.h>
+
#include <linux/if_link.h>
+
+#include <linux/types.h>
+
#include <arpa/inet.h>
+
+#include <linux/in6.h>
+
+#include <linux/if_tunnel.h>
+
+
#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;
+7 -1
pkgs/os-specific/linux/iproute/default.nix
···
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
-164
pkgs/os-specific/linux/iproute/ubuntu-fan.patch
···
-
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);
+2 -7
pkgs/os-specific/linux/kernel/patches.nix
···
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 =
-616
pkgs/os-specific/linux/kernel/ubuntu-fan-3.patch
···
-
From f3c956096902669c3529cb01d40deb0c759ed94f Mon Sep 17 00:00:00 2001
-
From: Jay Vosburgh <jay.vosburgh@canonical.com>
-
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 <jay.vosburgh@canonical.com>
-
[apw@canonical.com: move IFLA_IPTUN_FAN_UNDERLAY up to avoid clashing
-
with future feature additions.]
-
Signed-off-by: Andy Whitcroft <apw@canonical.com>
-
---
-
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 <apw@canonical.com>
-
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 <jay.vosburgh@canonical.com>
-
Signed-off-by: Andy Whitcroft <apw@canonical.com>
-
Acked-by: Tim Gardner <tim.gardner@canonical.com>
-
Acked-by: Brad Figg <brad.figg@canonical.com>
-
Signed-off-by: Brad Figg <brad.figg@canonical.com>
-
---
-
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 <linux/init.h>
-
#include <linux/netfilter_ipv4.h>
-
#include <linux/if_ether.h>
-
+#include <linux/inetdevice.h>
-
-
#include <net/sock.h>
-
#include <net/ip.h>
-
@@ -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
-
+1240
pkgs/os-specific/linux/kernel/ubuntu-fan-4.4.patch
···
+
From e64058be3b97c5bd3e034fc4ece21e306ef6f90b Mon Sep 17 00:00:00 2001
+
From: Jay Vosburgh <jay.vosburgh@canonical.com>
+
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 <jay.vosburgh@canonical.com>
+
Signed-off-by: Andy Whitcroft <apw@canonical.com>
+
Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
+
+
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 <linux/init.h>
+
#include <linux/netfilter_ipv4.h>
+
#include <linux/if_ether.h>
+
+#include <linux/inetdevice.h>
+
+
#include <net/sock.h>
+
#include <net/ip.h>
+
@@ -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 <jay.vosburgh@canonical.com>
+
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 <jay.vosburgh@canonical.com>
+
[apw@canonical.com: added feature marker for fan over vxlan.]
+
Signed-off-by: Andy Whitcroft <apw@canonical.com>
+
---
+
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 <linux/udp.h>
+
#include <linux/igmp.h>
+
#include <linux/etherdevice.h>
+
+#include <linux/inetdevice.h>
+
#include <linux/if_ether.h>
+
#include <linux/if_vlan.h>
+
#include <linux/hash.h>
+
@@ -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 <linux/netfilter_ipv4.h>
+
#include <linux/if_ether.h>
+
#include <linux/inetdevice.h>
+
+#include <linux/rculist.h>
+
+
#include <net/sock.h>
+
#include <net/ip.h>
+
@@ -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
+
-616
pkgs/os-specific/linux/kernel/ubuntu-fan-4.patch
···
-
From f3c956096902669c3529cb01d40deb0c759ed94f Mon Sep 17 00:00:00 2001
-
From: Jay Vosburgh <jay.vosburgh@canonical.com>
-
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 <jay.vosburgh@canonical.com>
-
[apw@canonical.com: move IFLA_IPTUN_FAN_UNDERLAY up to avoid clashing
-
with future feature additions.]
-
Signed-off-by: Andy Whitcroft <apw@canonical.com>
-
---
-
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 <apw@canonical.com>
-
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 <jay.vosburgh@canonical.com>
-
Signed-off-by: Andy Whitcroft <apw@canonical.com>
-
Acked-by: Tim Gardner <tim.gardner@canonical.com>
-
Acked-by: Brad Figg <brad.figg@canonical.com>
-
Signed-off-by: Brad Figg <brad.figg@canonical.com>
-
---
-
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 <linux/init.h>
-
#include <linux/netfilter_ipv4.h>
-
#include <linux/if_ether.h>
-
+#include <linux/inetdevice.h>
-
-
#include <net/sock.h>
-
#include <net/ip.h>
-
@@ -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
-