Commit 20da848f authored by David S. Miller's avatar David S. Miller

Merge branch 'iptunnel-policy-based-routing'

Craig Gallek says:

====================
ip_tunnel: Allow policy-based routing through tunnels

iproute2 changes to follow.  Example usage:
  ip link add gre-test type gre local 10.0.0.1 remote 10.0.0.2 fwmark 0x4
  ip -detail link show gre-test
  ...
  ip link set gre-test type gre fwmark 0
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 8e6c1812 9830ad4c
...@@ -33,6 +33,8 @@ struct __ip6_tnl_parm { ...@@ -33,6 +33,8 @@ struct __ip6_tnl_parm {
__be16 o_flags; __be16 o_flags;
__be32 i_key; __be32 i_key;
__be32 o_key; __be32 o_key;
__u32 fwmark;
}; };
/* IPv6 tunnel */ /* IPv6 tunnel */
......
...@@ -132,6 +132,7 @@ struct ip_tunnel { ...@@ -132,6 +132,7 @@ struct ip_tunnel {
unsigned int prl_count; /* # of entries in PRL */ unsigned int prl_count; /* # of entries in PRL */
unsigned int ip_tnl_net_id; unsigned int ip_tnl_net_id;
struct gro_cells gro_cells; struct gro_cells gro_cells;
__u32 fwmark;
bool collect_md; bool collect_md;
bool ignore_df; bool ignore_df;
}; };
...@@ -273,9 +274,9 @@ int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb, ...@@ -273,9 +274,9 @@ int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb,
const struct tnl_ptk_info *tpi, struct metadata_dst *tun_dst, const struct tnl_ptk_info *tpi, struct metadata_dst *tun_dst,
bool log_ecn_error); bool log_ecn_error);
int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[], int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[],
struct ip_tunnel_parm *p); struct ip_tunnel_parm *p, __u32 fwmark);
int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[], int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],
struct ip_tunnel_parm *p); struct ip_tunnel_parm *p, __u32 fwmark);
void ip_tunnel_setup(struct net_device *dev, unsigned int net_id); void ip_tunnel_setup(struct net_device *dev, unsigned int net_id);
struct ip_tunnel_encap_ops { struct ip_tunnel_encap_ops {
......
...@@ -75,6 +75,7 @@ enum { ...@@ -75,6 +75,7 @@ enum {
IFLA_IPTUN_ENCAP_SPORT, IFLA_IPTUN_ENCAP_SPORT,
IFLA_IPTUN_ENCAP_DPORT, IFLA_IPTUN_ENCAP_DPORT,
IFLA_IPTUN_COLLECT_METADATA, IFLA_IPTUN_COLLECT_METADATA,
IFLA_IPTUN_FWMARK,
__IFLA_IPTUN_MAX, __IFLA_IPTUN_MAX,
}; };
#define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1) #define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1)
...@@ -132,6 +133,7 @@ enum { ...@@ -132,6 +133,7 @@ enum {
IFLA_GRE_ENCAP_DPORT, IFLA_GRE_ENCAP_DPORT,
IFLA_GRE_COLLECT_METADATA, IFLA_GRE_COLLECT_METADATA,
IFLA_GRE_IGNORE_DF, IFLA_GRE_IGNORE_DF,
IFLA_GRE_FWMARK,
__IFLA_GRE_MAX, __IFLA_GRE_MAX,
}; };
...@@ -147,6 +149,7 @@ enum { ...@@ -147,6 +149,7 @@ enum {
IFLA_VTI_OKEY, IFLA_VTI_OKEY,
IFLA_VTI_LOCAL, IFLA_VTI_LOCAL,
IFLA_VTI_REMOTE, IFLA_VTI_REMOTE,
IFLA_VTI_FWMARK,
__IFLA_VTI_MAX, __IFLA_VTI_MAX,
}; };
......
...@@ -829,7 +829,8 @@ static int ipgre_tap_validate(struct nlattr *tb[], struct nlattr *data[]) ...@@ -829,7 +829,8 @@ static int ipgre_tap_validate(struct nlattr *tb[], struct nlattr *data[])
static int ipgre_netlink_parms(struct net_device *dev, static int ipgre_netlink_parms(struct net_device *dev,
struct nlattr *data[], struct nlattr *data[],
struct nlattr *tb[], struct nlattr *tb[],
struct ip_tunnel_parm *parms) struct ip_tunnel_parm *parms,
__u32 *fwmark)
{ {
struct ip_tunnel *t = netdev_priv(dev); struct ip_tunnel *t = netdev_priv(dev);
...@@ -886,6 +887,9 @@ static int ipgre_netlink_parms(struct net_device *dev, ...@@ -886,6 +887,9 @@ static int ipgre_netlink_parms(struct net_device *dev,
t->ignore_df = !!nla_get_u8(data[IFLA_GRE_IGNORE_DF]); t->ignore_df = !!nla_get_u8(data[IFLA_GRE_IGNORE_DF]);
} }
if (data[IFLA_GRE_FWMARK])
*fwmark = nla_get_u32(data[IFLA_GRE_FWMARK]);
return 0; return 0;
} }
...@@ -957,6 +961,7 @@ static int ipgre_newlink(struct net *src_net, struct net_device *dev, ...@@ -957,6 +961,7 @@ static int ipgre_newlink(struct net *src_net, struct net_device *dev,
{ {
struct ip_tunnel_parm p; struct ip_tunnel_parm p;
struct ip_tunnel_encap ipencap; struct ip_tunnel_encap ipencap;
__u32 fwmark = 0;
int err; int err;
if (ipgre_netlink_encap_parms(data, &ipencap)) { if (ipgre_netlink_encap_parms(data, &ipencap)) {
...@@ -967,31 +972,32 @@ static int ipgre_newlink(struct net *src_net, struct net_device *dev, ...@@ -967,31 +972,32 @@ static int ipgre_newlink(struct net *src_net, struct net_device *dev,
return err; return err;
} }
err = ipgre_netlink_parms(dev, data, tb, &p); err = ipgre_netlink_parms(dev, data, tb, &p, &fwmark);
if (err < 0) if (err < 0)
return err; return err;
return ip_tunnel_newlink(dev, tb, &p); return ip_tunnel_newlink(dev, tb, &p, fwmark);
} }
static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[], static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
struct nlattr *data[]) struct nlattr *data[])
{ {
struct ip_tunnel *t = netdev_priv(dev);
struct ip_tunnel_parm p; struct ip_tunnel_parm p;
struct ip_tunnel_encap ipencap; struct ip_tunnel_encap ipencap;
__u32 fwmark = t->fwmark;
int err; int err;
if (ipgre_netlink_encap_parms(data, &ipencap)) { if (ipgre_netlink_encap_parms(data, &ipencap)) {
struct ip_tunnel *t = netdev_priv(dev);
err = ip_tunnel_encap_setup(t, &ipencap); err = ip_tunnel_encap_setup(t, &ipencap);
if (err < 0) if (err < 0)
return err; return err;
} }
err = ipgre_netlink_parms(dev, data, tb, &p); err = ipgre_netlink_parms(dev, data, tb, &p, &fwmark);
if (err < 0) if (err < 0)
return err; return err;
return ip_tunnel_changelink(dev, tb, &p); return ip_tunnel_changelink(dev, tb, &p, fwmark);
} }
static size_t ipgre_get_size(const struct net_device *dev) static size_t ipgre_get_size(const struct net_device *dev)
...@@ -1029,6 +1035,8 @@ static size_t ipgre_get_size(const struct net_device *dev) ...@@ -1029,6 +1035,8 @@ static size_t ipgre_get_size(const struct net_device *dev)
nla_total_size(0) + nla_total_size(0) +
/* IFLA_GRE_IGNORE_DF */ /* IFLA_GRE_IGNORE_DF */
nla_total_size(1) + nla_total_size(1) +
/* IFLA_GRE_FWMARK */
nla_total_size(4) +
0; 0;
} }
...@@ -1049,7 +1057,8 @@ static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev) ...@@ -1049,7 +1057,8 @@ static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
nla_put_u8(skb, IFLA_GRE_TTL, p->iph.ttl) || nla_put_u8(skb, IFLA_GRE_TTL, p->iph.ttl) ||
nla_put_u8(skb, IFLA_GRE_TOS, p->iph.tos) || nla_put_u8(skb, IFLA_GRE_TOS, p->iph.tos) ||
nla_put_u8(skb, IFLA_GRE_PMTUDISC, nla_put_u8(skb, IFLA_GRE_PMTUDISC,
!!(p->iph.frag_off & htons(IP_DF)))) !!(p->iph.frag_off & htons(IP_DF))) ||
nla_put_u32(skb, IFLA_GRE_FWMARK, t->fwmark))
goto nla_put_failure; goto nla_put_failure;
if (nla_put_u16(skb, IFLA_GRE_ENCAP_TYPE, if (nla_put_u16(skb, IFLA_GRE_ENCAP_TYPE,
...@@ -1093,6 +1102,7 @@ static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = { ...@@ -1093,6 +1102,7 @@ static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = {
[IFLA_GRE_ENCAP_DPORT] = { .type = NLA_U16 }, [IFLA_GRE_ENCAP_DPORT] = { .type = NLA_U16 },
[IFLA_GRE_COLLECT_METADATA] = { .type = NLA_FLAG }, [IFLA_GRE_COLLECT_METADATA] = { .type = NLA_FLAG },
[IFLA_GRE_IGNORE_DF] = { .type = NLA_U8 }, [IFLA_GRE_IGNORE_DF] = { .type = NLA_U8 },
[IFLA_GRE_FWMARK] = { .type = NLA_U32 },
}; };
static struct rtnl_link_ops ipgre_link_ops __read_mostly = { static struct rtnl_link_ops ipgre_link_ops __read_mostly = {
......
...@@ -293,7 +293,8 @@ static struct net_device *__ip_tunnel_create(struct net *net, ...@@ -293,7 +293,8 @@ static struct net_device *__ip_tunnel_create(struct net *net,
static inline void init_tunnel_flow(struct flowi4 *fl4, static inline void init_tunnel_flow(struct flowi4 *fl4,
int proto, int proto,
__be32 daddr, __be32 saddr, __be32 daddr, __be32 saddr,
__be32 key, __u8 tos, int oif) __be32 key, __u8 tos, int oif,
__u32 mark)
{ {
memset(fl4, 0, sizeof(*fl4)); memset(fl4, 0, sizeof(*fl4));
fl4->flowi4_oif = oif; fl4->flowi4_oif = oif;
...@@ -302,6 +303,7 @@ static inline void init_tunnel_flow(struct flowi4 *fl4, ...@@ -302,6 +303,7 @@ static inline void init_tunnel_flow(struct flowi4 *fl4,
fl4->flowi4_tos = tos; fl4->flowi4_tos = tos;
fl4->flowi4_proto = proto; fl4->flowi4_proto = proto;
fl4->fl4_gre_key = key; fl4->fl4_gre_key = key;
fl4->flowi4_mark = mark;
} }
static int ip_tunnel_bind_dev(struct net_device *dev) static int ip_tunnel_bind_dev(struct net_device *dev)
...@@ -322,7 +324,8 @@ static int ip_tunnel_bind_dev(struct net_device *dev) ...@@ -322,7 +324,8 @@ static int ip_tunnel_bind_dev(struct net_device *dev)
init_tunnel_flow(&fl4, iph->protocol, iph->daddr, init_tunnel_flow(&fl4, iph->protocol, iph->daddr,
iph->saddr, tunnel->parms.o_key, iph->saddr, tunnel->parms.o_key,
RT_TOS(iph->tos), tunnel->parms.link); RT_TOS(iph->tos), tunnel->parms.link,
tunnel->fwmark);
rt = ip_route_output_key(tunnel->net, &fl4); rt = ip_route_output_key(tunnel->net, &fl4);
if (!IS_ERR(rt)) { if (!IS_ERR(rt)) {
...@@ -578,7 +581,7 @@ void ip_md_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, u8 proto) ...@@ -578,7 +581,7 @@ void ip_md_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, u8 proto)
tos = ipv6_get_dsfield((const struct ipv6hdr *)inner_iph); tos = ipv6_get_dsfield((const struct ipv6hdr *)inner_iph);
} }
init_tunnel_flow(&fl4, proto, key->u.ipv4.dst, key->u.ipv4.src, 0, init_tunnel_flow(&fl4, proto, key->u.ipv4.dst, key->u.ipv4.src, 0,
RT_TOS(tos), tunnel->parms.link); RT_TOS(tos), tunnel->parms.link, tunnel->fwmark);
if (tunnel->encap.type != TUNNEL_ENCAP_NONE) if (tunnel->encap.type != TUNNEL_ENCAP_NONE)
goto tx_error; goto tx_error;
rt = ip_route_output_key(tunnel->net, &fl4); rt = ip_route_output_key(tunnel->net, &fl4);
...@@ -707,7 +710,8 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, ...@@ -707,7 +710,8 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
} }
init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr, init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr,
tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link); tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link,
tunnel->fwmark);
if (ip_tunnel_encap(skb, tunnel, &protocol, &fl4) < 0) if (ip_tunnel_encap(skb, tunnel, &protocol, &fl4) < 0)
goto tx_error; goto tx_error;
...@@ -795,7 +799,8 @@ static void ip_tunnel_update(struct ip_tunnel_net *itn, ...@@ -795,7 +799,8 @@ static void ip_tunnel_update(struct ip_tunnel_net *itn,
struct ip_tunnel *t, struct ip_tunnel *t,
struct net_device *dev, struct net_device *dev,
struct ip_tunnel_parm *p, struct ip_tunnel_parm *p,
bool set_mtu) bool set_mtu,
__u32 fwmark)
{ {
ip_tunnel_del(itn, t); ip_tunnel_del(itn, t);
t->parms.iph.saddr = p->iph.saddr; t->parms.iph.saddr = p->iph.saddr;
...@@ -812,10 +817,11 @@ static void ip_tunnel_update(struct ip_tunnel_net *itn, ...@@ -812,10 +817,11 @@ static void ip_tunnel_update(struct ip_tunnel_net *itn,
t->parms.iph.tos = p->iph.tos; t->parms.iph.tos = p->iph.tos;
t->parms.iph.frag_off = p->iph.frag_off; t->parms.iph.frag_off = p->iph.frag_off;
if (t->parms.link != p->link) { if (t->parms.link != p->link || t->fwmark != fwmark) {
int mtu; int mtu;
t->parms.link = p->link; t->parms.link = p->link;
t->fwmark = fwmark;
mtu = ip_tunnel_bind_dev(dev); mtu = ip_tunnel_bind_dev(dev);
if (set_mtu) if (set_mtu)
dev->mtu = mtu; dev->mtu = mtu;
...@@ -893,7 +899,7 @@ int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd) ...@@ -893,7 +899,7 @@ int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd)
if (t) { if (t) {
err = 0; err = 0;
ip_tunnel_update(itn, t, dev, p, true); ip_tunnel_update(itn, t, dev, p, true, 0);
} else { } else {
err = -ENOENT; err = -ENOENT;
} }
...@@ -1066,7 +1072,7 @@ void ip_tunnel_delete_net(struct ip_tunnel_net *itn, struct rtnl_link_ops *ops) ...@@ -1066,7 +1072,7 @@ void ip_tunnel_delete_net(struct ip_tunnel_net *itn, struct rtnl_link_ops *ops)
EXPORT_SYMBOL_GPL(ip_tunnel_delete_net); EXPORT_SYMBOL_GPL(ip_tunnel_delete_net);
int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[], int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],
struct ip_tunnel_parm *p) struct ip_tunnel_parm *p, __u32 fwmark)
{ {
struct ip_tunnel *nt; struct ip_tunnel *nt;
struct net *net = dev_net(dev); struct net *net = dev_net(dev);
...@@ -1087,6 +1093,7 @@ int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[], ...@@ -1087,6 +1093,7 @@ int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],
nt->net = net; nt->net = net;
nt->parms = *p; nt->parms = *p;
nt->fwmark = fwmark;
err = register_netdevice(dev); err = register_netdevice(dev);
if (err) if (err)
goto out; goto out;
...@@ -1105,7 +1112,7 @@ int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[], ...@@ -1105,7 +1112,7 @@ int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],
EXPORT_SYMBOL_GPL(ip_tunnel_newlink); EXPORT_SYMBOL_GPL(ip_tunnel_newlink);
int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[], int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[],
struct ip_tunnel_parm *p) struct ip_tunnel_parm *p, __u32 fwmark)
{ {
struct ip_tunnel *t; struct ip_tunnel *t;
struct ip_tunnel *tunnel = netdev_priv(dev); struct ip_tunnel *tunnel = netdev_priv(dev);
...@@ -1137,7 +1144,7 @@ int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[], ...@@ -1137,7 +1144,7 @@ int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[],
} }
} }
ip_tunnel_update(itn, t, dev, p, !tb[IFLA_MTU]); ip_tunnel_update(itn, t, dev, p, !tb[IFLA_MTU], fwmark);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(ip_tunnel_changelink); EXPORT_SYMBOL_GPL(ip_tunnel_changelink);
......
...@@ -471,7 +471,8 @@ static int vti_tunnel_validate(struct nlattr *tb[], struct nlattr *data[]) ...@@ -471,7 +471,8 @@ static int vti_tunnel_validate(struct nlattr *tb[], struct nlattr *data[])
} }
static void vti_netlink_parms(struct nlattr *data[], static void vti_netlink_parms(struct nlattr *data[],
struct ip_tunnel_parm *parms) struct ip_tunnel_parm *parms,
__u32 *fwmark)
{ {
memset(parms, 0, sizeof(*parms)); memset(parms, 0, sizeof(*parms));
...@@ -497,24 +498,29 @@ static void vti_netlink_parms(struct nlattr *data[], ...@@ -497,24 +498,29 @@ static void vti_netlink_parms(struct nlattr *data[],
if (data[IFLA_VTI_REMOTE]) if (data[IFLA_VTI_REMOTE])
parms->iph.daddr = nla_get_in_addr(data[IFLA_VTI_REMOTE]); parms->iph.daddr = nla_get_in_addr(data[IFLA_VTI_REMOTE]);
if (data[IFLA_VTI_FWMARK])
*fwmark = nla_get_u32(data[IFLA_VTI_FWMARK]);
} }
static int vti_newlink(struct net *src_net, struct net_device *dev, static int vti_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[]) struct nlattr *tb[], struct nlattr *data[])
{ {
struct ip_tunnel_parm parms; struct ip_tunnel_parm parms;
__u32 fwmark = 0;
vti_netlink_parms(data, &parms); vti_netlink_parms(data, &parms, &fwmark);
return ip_tunnel_newlink(dev, tb, &parms); return ip_tunnel_newlink(dev, tb, &parms, fwmark);
} }
static int vti_changelink(struct net_device *dev, struct nlattr *tb[], static int vti_changelink(struct net_device *dev, struct nlattr *tb[],
struct nlattr *data[]) struct nlattr *data[])
{ {
struct ip_tunnel *t = netdev_priv(dev);
__u32 fwmark = t->fwmark;
struct ip_tunnel_parm p; struct ip_tunnel_parm p;
vti_netlink_parms(data, &p); vti_netlink_parms(data, &p, &fwmark);
return ip_tunnel_changelink(dev, tb, &p); return ip_tunnel_changelink(dev, tb, &p, fwmark);
} }
static size_t vti_get_size(const struct net_device *dev) static size_t vti_get_size(const struct net_device *dev)
...@@ -530,6 +536,8 @@ static size_t vti_get_size(const struct net_device *dev) ...@@ -530,6 +536,8 @@ static size_t vti_get_size(const struct net_device *dev)
nla_total_size(4) + nla_total_size(4) +
/* IFLA_VTI_REMOTE */ /* IFLA_VTI_REMOTE */
nla_total_size(4) + nla_total_size(4) +
/* IFLA_VTI_FWMARK */
nla_total_size(4) +
0; 0;
} }
...@@ -543,6 +551,7 @@ static int vti_fill_info(struct sk_buff *skb, const struct net_device *dev) ...@@ -543,6 +551,7 @@ static int vti_fill_info(struct sk_buff *skb, const struct net_device *dev)
nla_put_be32(skb, IFLA_VTI_OKEY, p->o_key); nla_put_be32(skb, IFLA_VTI_OKEY, p->o_key);
nla_put_in_addr(skb, IFLA_VTI_LOCAL, p->iph.saddr); nla_put_in_addr(skb, IFLA_VTI_LOCAL, p->iph.saddr);
nla_put_in_addr(skb, IFLA_VTI_REMOTE, p->iph.daddr); nla_put_in_addr(skb, IFLA_VTI_REMOTE, p->iph.daddr);
nla_put_u32(skb, IFLA_VTI_FWMARK, t->fwmark);
return 0; return 0;
} }
...@@ -553,6 +562,7 @@ static const struct nla_policy vti_policy[IFLA_VTI_MAX + 1] = { ...@@ -553,6 +562,7 @@ static const struct nla_policy vti_policy[IFLA_VTI_MAX + 1] = {
[IFLA_VTI_OKEY] = { .type = NLA_U32 }, [IFLA_VTI_OKEY] = { .type = NLA_U32 },
[IFLA_VTI_LOCAL] = { .len = FIELD_SIZEOF(struct iphdr, saddr) }, [IFLA_VTI_LOCAL] = { .len = FIELD_SIZEOF(struct iphdr, saddr) },
[IFLA_VTI_REMOTE] = { .len = FIELD_SIZEOF(struct iphdr, daddr) }, [IFLA_VTI_REMOTE] = { .len = FIELD_SIZEOF(struct iphdr, daddr) },
[IFLA_VTI_FWMARK] = { .type = NLA_U32 },
}; };
static struct rtnl_link_ops vti_link_ops __read_mostly = { static struct rtnl_link_ops vti_link_ops __read_mostly = {
......
...@@ -390,7 +390,8 @@ static int ipip_tunnel_validate(struct nlattr *tb[], struct nlattr *data[]) ...@@ -390,7 +390,8 @@ static int ipip_tunnel_validate(struct nlattr *tb[], struct nlattr *data[])
} }
static void ipip_netlink_parms(struct nlattr *data[], static void ipip_netlink_parms(struct nlattr *data[],
struct ip_tunnel_parm *parms, bool *collect_md) struct ip_tunnel_parm *parms, bool *collect_md,
__u32 *fwmark)
{ {
memset(parms, 0, sizeof(*parms)); memset(parms, 0, sizeof(*parms));
...@@ -428,6 +429,9 @@ static void ipip_netlink_parms(struct nlattr *data[], ...@@ -428,6 +429,9 @@ static void ipip_netlink_parms(struct nlattr *data[],
if (data[IFLA_IPTUN_COLLECT_METADATA]) if (data[IFLA_IPTUN_COLLECT_METADATA])
*collect_md = true; *collect_md = true;
if (data[IFLA_IPTUN_FWMARK])
*fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]);
} }
/* This function returns true when ENCAP attributes are present in the nl msg */ /* This function returns true when ENCAP attributes are present in the nl msg */
...@@ -470,6 +474,7 @@ static int ipip_newlink(struct net *src_net, struct net_device *dev, ...@@ -470,6 +474,7 @@ static int ipip_newlink(struct net *src_net, struct net_device *dev,
struct ip_tunnel *t = netdev_priv(dev); struct ip_tunnel *t = netdev_priv(dev);
struct ip_tunnel_parm p; struct ip_tunnel_parm p;
struct ip_tunnel_encap ipencap; struct ip_tunnel_encap ipencap;
__u32 fwmark = 0;
if (ipip_netlink_encap_parms(data, &ipencap)) { if (ipip_netlink_encap_parms(data, &ipencap)) {
int err = ip_tunnel_encap_setup(t, &ipencap); int err = ip_tunnel_encap_setup(t, &ipencap);
...@@ -478,26 +483,27 @@ static int ipip_newlink(struct net *src_net, struct net_device *dev, ...@@ -478,26 +483,27 @@ static int ipip_newlink(struct net *src_net, struct net_device *dev,
return err; return err;
} }
ipip_netlink_parms(data, &p, &t->collect_md); ipip_netlink_parms(data, &p, &t->collect_md, &fwmark);
return ip_tunnel_newlink(dev, tb, &p); return ip_tunnel_newlink(dev, tb, &p, fwmark);
} }
static int ipip_changelink(struct net_device *dev, struct nlattr *tb[], static int ipip_changelink(struct net_device *dev, struct nlattr *tb[],
struct nlattr *data[]) struct nlattr *data[])
{ {
struct ip_tunnel *t = netdev_priv(dev);
struct ip_tunnel_parm p; struct ip_tunnel_parm p;
struct ip_tunnel_encap ipencap; struct ip_tunnel_encap ipencap;
bool collect_md; bool collect_md;
__u32 fwmark = t->fwmark;
if (ipip_netlink_encap_parms(data, &ipencap)) { if (ipip_netlink_encap_parms(data, &ipencap)) {
struct ip_tunnel *t = netdev_priv(dev);
int err = ip_tunnel_encap_setup(t, &ipencap); int err = ip_tunnel_encap_setup(t, &ipencap);
if (err < 0) if (err < 0)
return err; return err;
} }
ipip_netlink_parms(data, &p, &collect_md); ipip_netlink_parms(data, &p, &collect_md, &fwmark);
if (collect_md) if (collect_md)
return -EINVAL; return -EINVAL;
...@@ -505,7 +511,7 @@ static int ipip_changelink(struct net_device *dev, struct nlattr *tb[], ...@@ -505,7 +511,7 @@ static int ipip_changelink(struct net_device *dev, struct nlattr *tb[],
(!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr)) (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr))
return -EINVAL; return -EINVAL;
return ip_tunnel_changelink(dev, tb, &p); return ip_tunnel_changelink(dev, tb, &p, fwmark);
} }
static size_t ipip_get_size(const struct net_device *dev) static size_t ipip_get_size(const struct net_device *dev)
...@@ -535,6 +541,8 @@ static size_t ipip_get_size(const struct net_device *dev) ...@@ -535,6 +541,8 @@ static size_t ipip_get_size(const struct net_device *dev)
nla_total_size(2) + nla_total_size(2) +
/* IFLA_IPTUN_COLLECT_METADATA */ /* IFLA_IPTUN_COLLECT_METADATA */
nla_total_size(0) + nla_total_size(0) +
/* IFLA_IPTUN_FWMARK */
nla_total_size(4) +
0; 0;
} }
...@@ -550,7 +558,8 @@ static int ipip_fill_info(struct sk_buff *skb, const struct net_device *dev) ...@@ -550,7 +558,8 @@ static int ipip_fill_info(struct sk_buff *skb, const struct net_device *dev)
nla_put_u8(skb, IFLA_IPTUN_TOS, parm->iph.tos) || nla_put_u8(skb, IFLA_IPTUN_TOS, parm->iph.tos) ||
nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->iph.protocol) || nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->iph.protocol) ||
nla_put_u8(skb, IFLA_IPTUN_PMTUDISC, nla_put_u8(skb, IFLA_IPTUN_PMTUDISC,
!!(parm->iph.frag_off & htons(IP_DF)))) !!(parm->iph.frag_off & htons(IP_DF))) ||
nla_put_u32(skb, IFLA_IPTUN_FWMARK, tunnel->fwmark))
goto nla_put_failure; goto nla_put_failure;
if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE, if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE,
...@@ -585,6 +594,7 @@ static const struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = { ...@@ -585,6 +594,7 @@ static const struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = {
[IFLA_IPTUN_ENCAP_SPORT] = { .type = NLA_U16 }, [IFLA_IPTUN_ENCAP_SPORT] = { .type = NLA_U16 },
[IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 }, [IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 },
[IFLA_IPTUN_COLLECT_METADATA] = { .type = NLA_FLAG }, [IFLA_IPTUN_COLLECT_METADATA] = { .type = NLA_FLAG },
[IFLA_IPTUN_FWMARK] = { .type = NLA_U32 },
}; };
static struct rtnl_link_ops ipip_link_ops __read_mostly = { static struct rtnl_link_ops ipip_link_ops __read_mostly = {
......
...@@ -544,6 +544,8 @@ static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev) ...@@ -544,6 +544,8 @@ static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev)
& IPV6_TCLASS_MASK; & IPV6_TCLASS_MASK;
if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK) if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
fl6.flowi6_mark = skb->mark; fl6.flowi6_mark = skb->mark;
else
fl6.flowi6_mark = t->parms.fwmark;
fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL); fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
...@@ -603,6 +605,8 @@ static inline int ip6gre_xmit_ipv6(struct sk_buff *skb, struct net_device *dev) ...@@ -603,6 +605,8 @@ static inline int ip6gre_xmit_ipv6(struct sk_buff *skb, struct net_device *dev)
fl6.flowlabel |= ip6_flowlabel(ipv6h); fl6.flowlabel |= ip6_flowlabel(ipv6h);
if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK) if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
fl6.flowi6_mark = skb->mark; fl6.flowi6_mark = skb->mark;
else
fl6.flowi6_mark = t->parms.fwmark;
fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL); fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
...@@ -780,6 +784,7 @@ static int ip6gre_tnl_change(struct ip6_tnl *t, ...@@ -780,6 +784,7 @@ static int ip6gre_tnl_change(struct ip6_tnl *t,
t->parms.o_key = p->o_key; t->parms.o_key = p->o_key;
t->parms.i_flags = p->i_flags; t->parms.i_flags = p->i_flags;
t->parms.o_flags = p->o_flags; t->parms.o_flags = p->o_flags;
t->parms.fwmark = p->fwmark;
dst_cache_reset(&t->dst_cache); dst_cache_reset(&t->dst_cache);
ip6gre_tnl_link_config(t, set_mtu); ip6gre_tnl_link_config(t, set_mtu);
return 0; return 0;
...@@ -1249,6 +1254,9 @@ static void ip6gre_netlink_parms(struct nlattr *data[], ...@@ -1249,6 +1254,9 @@ static void ip6gre_netlink_parms(struct nlattr *data[],
if (data[IFLA_GRE_FLAGS]) if (data[IFLA_GRE_FLAGS])
parms->flags = nla_get_u32(data[IFLA_GRE_FLAGS]); parms->flags = nla_get_u32(data[IFLA_GRE_FLAGS]);
if (data[IFLA_GRE_FWMARK])
parms->fwmark = nla_get_u32(data[IFLA_GRE_FWMARK]);
} }
static int ip6gre_tap_init(struct net_device *dev) static int ip6gre_tap_init(struct net_device *dev)
...@@ -1470,6 +1478,8 @@ static size_t ip6gre_get_size(const struct net_device *dev) ...@@ -1470,6 +1478,8 @@ static size_t ip6gre_get_size(const struct net_device *dev)
nla_total_size(2) + nla_total_size(2) +
/* IFLA_GRE_ENCAP_DPORT */ /* IFLA_GRE_ENCAP_DPORT */
nla_total_size(2) + nla_total_size(2) +
/* IFLA_GRE_FWMARK */
nla_total_size(4) +
0; 0;
} }
...@@ -1490,7 +1500,8 @@ static int ip6gre_fill_info(struct sk_buff *skb, const struct net_device *dev) ...@@ -1490,7 +1500,8 @@ static int ip6gre_fill_info(struct sk_buff *skb, const struct net_device *dev)
nla_put_u8(skb, IFLA_GRE_TTL, p->hop_limit) || nla_put_u8(skb, IFLA_GRE_TTL, p->hop_limit) ||
nla_put_u8(skb, IFLA_GRE_ENCAP_LIMIT, p->encap_limit) || nla_put_u8(skb, IFLA_GRE_ENCAP_LIMIT, p->encap_limit) ||
nla_put_be32(skb, IFLA_GRE_FLOWINFO, p->flowinfo) || nla_put_be32(skb, IFLA_GRE_FLOWINFO, p->flowinfo) ||
nla_put_u32(skb, IFLA_GRE_FLAGS, p->flags)) nla_put_u32(skb, IFLA_GRE_FLAGS, p->flags) ||
nla_put_u32(skb, IFLA_GRE_FWMARK, p->fwmark))
goto nla_put_failure; goto nla_put_failure;
if (nla_put_u16(skb, IFLA_GRE_ENCAP_TYPE, if (nla_put_u16(skb, IFLA_GRE_ENCAP_TYPE,
...@@ -1525,6 +1536,7 @@ static const struct nla_policy ip6gre_policy[IFLA_GRE_MAX + 1] = { ...@@ -1525,6 +1536,7 @@ static const struct nla_policy ip6gre_policy[IFLA_GRE_MAX + 1] = {
[IFLA_GRE_ENCAP_FLAGS] = { .type = NLA_U16 }, [IFLA_GRE_ENCAP_FLAGS] = { .type = NLA_U16 },
[IFLA_GRE_ENCAP_SPORT] = { .type = NLA_U16 }, [IFLA_GRE_ENCAP_SPORT] = { .type = NLA_U16 },
[IFLA_GRE_ENCAP_DPORT] = { .type = NLA_U16 }, [IFLA_GRE_ENCAP_DPORT] = { .type = NLA_U16 },
[IFLA_GRE_FWMARK] = { .type = NLA_U32 },
}; };
static struct rtnl_link_ops ip6gre_link_ops __read_mostly = { static struct rtnl_link_ops ip6gre_link_ops __read_mostly = {
......
...@@ -1256,6 +1256,8 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -1256,6 +1256,8 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
& IPV6_TCLASS_MASK; & IPV6_TCLASS_MASK;
if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK) if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
fl6.flowi6_mark = skb->mark; fl6.flowi6_mark = skb->mark;
else
fl6.flowi6_mark = t->parms.fwmark;
} }
fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL); fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
...@@ -1338,6 +1340,8 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -1338,6 +1340,8 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
fl6.flowlabel |= ip6_flowlabel(ipv6h); fl6.flowlabel |= ip6_flowlabel(ipv6h);
if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK) if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
fl6.flowi6_mark = skb->mark; fl6.flowi6_mark = skb->mark;
else
fl6.flowi6_mark = t->parms.fwmark;
} }
fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL); fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
...@@ -1467,6 +1471,7 @@ ip6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p) ...@@ -1467,6 +1471,7 @@ ip6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p)
t->parms.flowinfo = p->flowinfo; t->parms.flowinfo = p->flowinfo;
t->parms.link = p->link; t->parms.link = p->link;
t->parms.proto = p->proto; t->parms.proto = p->proto;
t->parms.fwmark = p->fwmark;
dst_cache_reset(&t->dst_cache); dst_cache_reset(&t->dst_cache);
ip6_tnl_link_config(t); ip6_tnl_link_config(t);
return 0; return 0;
...@@ -1918,6 +1923,9 @@ static void ip6_tnl_netlink_parms(struct nlattr *data[], ...@@ -1918,6 +1923,9 @@ static void ip6_tnl_netlink_parms(struct nlattr *data[],
if (data[IFLA_IPTUN_COLLECT_METADATA]) if (data[IFLA_IPTUN_COLLECT_METADATA])
parms->collect_md = true; parms->collect_md = true;
if (data[IFLA_IPTUN_FWMARK])
parms->fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]);
} }
static bool ip6_tnl_netlink_encap_parms(struct nlattr *data[], static bool ip6_tnl_netlink_encap_parms(struct nlattr *data[],
...@@ -2054,6 +2062,8 @@ static size_t ip6_tnl_get_size(const struct net_device *dev) ...@@ -2054,6 +2062,8 @@ static size_t ip6_tnl_get_size(const struct net_device *dev)
nla_total_size(2) + nla_total_size(2) +
/* IFLA_IPTUN_COLLECT_METADATA */ /* IFLA_IPTUN_COLLECT_METADATA */
nla_total_size(0) + nla_total_size(0) +
/* IFLA_IPTUN_FWMARK */
nla_total_size(4) +
0; 0;
} }
...@@ -2069,7 +2079,8 @@ static int ip6_tnl_fill_info(struct sk_buff *skb, const struct net_device *dev) ...@@ -2069,7 +2079,8 @@ static int ip6_tnl_fill_info(struct sk_buff *skb, const struct net_device *dev)
nla_put_u8(skb, IFLA_IPTUN_ENCAP_LIMIT, parm->encap_limit) || nla_put_u8(skb, IFLA_IPTUN_ENCAP_LIMIT, parm->encap_limit) ||
nla_put_be32(skb, IFLA_IPTUN_FLOWINFO, parm->flowinfo) || nla_put_be32(skb, IFLA_IPTUN_FLOWINFO, parm->flowinfo) ||
nla_put_u32(skb, IFLA_IPTUN_FLAGS, parm->flags) || nla_put_u32(skb, IFLA_IPTUN_FLAGS, parm->flags) ||
nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto)) nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto) ||
nla_put_u32(skb, IFLA_IPTUN_FWMARK, parm->fwmark))
goto nla_put_failure; goto nla_put_failure;
if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE, tunnel->encap.type) || if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE, tunnel->encap.type) ||
...@@ -2081,6 +2092,7 @@ static int ip6_tnl_fill_info(struct sk_buff *skb, const struct net_device *dev) ...@@ -2081,6 +2092,7 @@ static int ip6_tnl_fill_info(struct sk_buff *skb, const struct net_device *dev)
if (parm->collect_md) if (parm->collect_md)
if (nla_put_flag(skb, IFLA_IPTUN_COLLECT_METADATA)) if (nla_put_flag(skb, IFLA_IPTUN_COLLECT_METADATA))
goto nla_put_failure; goto nla_put_failure;
return 0; return 0;
nla_put_failure: nla_put_failure:
...@@ -2109,6 +2121,7 @@ static const struct nla_policy ip6_tnl_policy[IFLA_IPTUN_MAX + 1] = { ...@@ -2109,6 +2121,7 @@ static const struct nla_policy ip6_tnl_policy[IFLA_IPTUN_MAX + 1] = {
[IFLA_IPTUN_ENCAP_SPORT] = { .type = NLA_U16 }, [IFLA_IPTUN_ENCAP_SPORT] = { .type = NLA_U16 },
[IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 }, [IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 },
[IFLA_IPTUN_COLLECT_METADATA] = { .type = NLA_FLAG }, [IFLA_IPTUN_COLLECT_METADATA] = { .type = NLA_FLAG },
[IFLA_IPTUN_FWMARK] = { .type = NLA_U32 },
}; };
static struct rtnl_link_ops ip6_link_ops __read_mostly = { static struct rtnl_link_ops ip6_link_ops __read_mostly = {
......
...@@ -657,6 +657,7 @@ vti6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p) ...@@ -657,6 +657,7 @@ vti6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p)
t->parms.i_key = p->i_key; t->parms.i_key = p->i_key;
t->parms.o_key = p->o_key; t->parms.o_key = p->o_key;
t->parms.proto = p->proto; t->parms.proto = p->proto;
t->parms.fwmark = p->fwmark;
dst_cache_reset(&t->dst_cache); dst_cache_reset(&t->dst_cache);
vti6_link_config(t); vti6_link_config(t);
return 0; return 0;
...@@ -933,6 +934,9 @@ static void vti6_netlink_parms(struct nlattr *data[], ...@@ -933,6 +934,9 @@ static void vti6_netlink_parms(struct nlattr *data[],
if (data[IFLA_VTI_OKEY]) if (data[IFLA_VTI_OKEY])
parms->o_key = nla_get_be32(data[IFLA_VTI_OKEY]); parms->o_key = nla_get_be32(data[IFLA_VTI_OKEY]);
if (data[IFLA_VTI_FWMARK])
parms->fwmark = nla_get_u32(data[IFLA_VTI_FWMARK]);
} }
static int vti6_newlink(struct net *src_net, struct net_device *dev, static int vti6_newlink(struct net *src_net, struct net_device *dev,
...@@ -998,6 +1002,8 @@ static size_t vti6_get_size(const struct net_device *dev) ...@@ -998,6 +1002,8 @@ static size_t vti6_get_size(const struct net_device *dev)
nla_total_size(4) + nla_total_size(4) +
/* IFLA_VTI_OKEY */ /* IFLA_VTI_OKEY */
nla_total_size(4) + nla_total_size(4) +
/* IFLA_VTI_FWMARK */
nla_total_size(4) +
0; 0;
} }
...@@ -1010,7 +1016,8 @@ static int vti6_fill_info(struct sk_buff *skb, const struct net_device *dev) ...@@ -1010,7 +1016,8 @@ static int vti6_fill_info(struct sk_buff *skb, const struct net_device *dev)
nla_put_in6_addr(skb, IFLA_VTI_LOCAL, &parm->laddr) || nla_put_in6_addr(skb, IFLA_VTI_LOCAL, &parm->laddr) ||
nla_put_in6_addr(skb, IFLA_VTI_REMOTE, &parm->raddr) || nla_put_in6_addr(skb, IFLA_VTI_REMOTE, &parm->raddr) ||
nla_put_be32(skb, IFLA_VTI_IKEY, parm->i_key) || nla_put_be32(skb, IFLA_VTI_IKEY, parm->i_key) ||
nla_put_be32(skb, IFLA_VTI_OKEY, parm->o_key)) nla_put_be32(skb, IFLA_VTI_OKEY, parm->o_key) ||
nla_put_u32(skb, IFLA_VTI_FWMARK, parm->fwmark))
goto nla_put_failure; goto nla_put_failure;
return 0; return 0;
...@@ -1024,6 +1031,7 @@ static const struct nla_policy vti6_policy[IFLA_VTI_MAX + 1] = { ...@@ -1024,6 +1031,7 @@ static const struct nla_policy vti6_policy[IFLA_VTI_MAX + 1] = {
[IFLA_VTI_REMOTE] = { .len = sizeof(struct in6_addr) }, [IFLA_VTI_REMOTE] = { .len = sizeof(struct in6_addr) },
[IFLA_VTI_IKEY] = { .type = NLA_U32 }, [IFLA_VTI_IKEY] = { .type = NLA_U32 },
[IFLA_VTI_OKEY] = { .type = NLA_U32 }, [IFLA_VTI_OKEY] = { .type = NLA_U32 },
[IFLA_VTI_FWMARK] = { .type = NLA_U32 },
}; };
static struct rtnl_link_ops vti6_link_ops __read_mostly = { static struct rtnl_link_ops vti6_link_ops __read_mostly = {
......
...@@ -881,11 +881,12 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, ...@@ -881,11 +881,12 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
goto tx_error; goto tx_error;
} }
rt = ip_route_output_ports(tunnel->net, &fl4, NULL, flowi4_init_output(&fl4, tunnel->parms.link, tunnel->fwmark,
dst, tiph->saddr, RT_TOS(tos), RT_SCOPE_UNIVERSE, IPPROTO_IPV6,
0, 0, 0, dst, tiph->saddr, 0, 0,
IPPROTO_IPV6, RT_TOS(tos), sock_net_uid(tunnel->net, NULL));
tunnel->parms.link); rt = ip_route_output_flow(tunnel->net, &fl4, NULL);
if (IS_ERR(rt)) { if (IS_ERR(rt)) {
dev->stats.tx_carrier_errors++; dev->stats.tx_carrier_errors++;
goto tx_error_icmp; goto tx_error_icmp;
...@@ -1071,7 +1072,8 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev) ...@@ -1071,7 +1072,8 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev)
} }
} }
static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p) static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p,
__u32 fwmark)
{ {
struct net *net = t->net; struct net *net = t->net;
struct sit_net *sitn = net_generic(net, sit_net_id); struct sit_net *sitn = net_generic(net, sit_net_id);
...@@ -1085,8 +1087,9 @@ static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p) ...@@ -1085,8 +1087,9 @@ static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p)
ipip6_tunnel_link(sitn, t); ipip6_tunnel_link(sitn, t);
t->parms.iph.ttl = p->iph.ttl; t->parms.iph.ttl = p->iph.ttl;
t->parms.iph.tos = p->iph.tos; t->parms.iph.tos = p->iph.tos;
if (t->parms.link != p->link) { if (t->parms.link != p->link || t->fwmark != fwmark) {
t->parms.link = p->link; t->parms.link = p->link;
t->fwmark = fwmark;
ipip6_tunnel_bind_dev(t->dev); ipip6_tunnel_bind_dev(t->dev);
} }
dst_cache_reset(&t->dst_cache); dst_cache_reset(&t->dst_cache);
...@@ -1220,7 +1223,7 @@ ipip6_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -1220,7 +1223,7 @@ ipip6_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
t = netdev_priv(dev); t = netdev_priv(dev);
} }
ipip6_tunnel_update(t, &p); ipip6_tunnel_update(t, &p, t->fwmark);
} }
if (t) { if (t) {
...@@ -1418,7 +1421,8 @@ static int ipip6_validate(struct nlattr *tb[], struct nlattr *data[]) ...@@ -1418,7 +1421,8 @@ static int ipip6_validate(struct nlattr *tb[], struct nlattr *data[])
} }
static void ipip6_netlink_parms(struct nlattr *data[], static void ipip6_netlink_parms(struct nlattr *data[],
struct ip_tunnel_parm *parms) struct ip_tunnel_parm *parms,
__u32 *fwmark)
{ {
memset(parms, 0, sizeof(*parms)); memset(parms, 0, sizeof(*parms));
...@@ -1457,6 +1461,8 @@ static void ipip6_netlink_parms(struct nlattr *data[], ...@@ -1457,6 +1461,8 @@ static void ipip6_netlink_parms(struct nlattr *data[],
if (data[IFLA_IPTUN_PROTO]) if (data[IFLA_IPTUN_PROTO])
parms->iph.protocol = nla_get_u8(data[IFLA_IPTUN_PROTO]); parms->iph.protocol = nla_get_u8(data[IFLA_IPTUN_PROTO]);
if (data[IFLA_IPTUN_FWMARK])
*fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]);
} }
/* This function returns true when ENCAP attributes are present in the nl msg */ /* This function returns true when ENCAP attributes are present in the nl msg */
...@@ -1549,7 +1555,7 @@ static int ipip6_newlink(struct net *src_net, struct net_device *dev, ...@@ -1549,7 +1555,7 @@ static int ipip6_newlink(struct net *src_net, struct net_device *dev,
return err; return err;
} }
ipip6_netlink_parms(data, &nt->parms); ipip6_netlink_parms(data, &nt->parms, &nt->fwmark);
if (ipip6_tunnel_locate(net, &nt->parms, 0)) if (ipip6_tunnel_locate(net, &nt->parms, 0))
return -EEXIST; return -EEXIST;
...@@ -1577,6 +1583,7 @@ static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[], ...@@ -1577,6 +1583,7 @@ static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[],
#ifdef CONFIG_IPV6_SIT_6RD #ifdef CONFIG_IPV6_SIT_6RD
struct ip_tunnel_6rd ip6rd; struct ip_tunnel_6rd ip6rd;
#endif #endif
__u32 fwmark = t->fwmark;
int err; int err;
if (dev == sitn->fb_tunnel_dev) if (dev == sitn->fb_tunnel_dev)
...@@ -1588,7 +1595,7 @@ static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[], ...@@ -1588,7 +1595,7 @@ static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[],
return err; return err;
} }
ipip6_netlink_parms(data, &p); ipip6_netlink_parms(data, &p, &fwmark);
if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) || if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) ||
(!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr)) (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr))
...@@ -1602,7 +1609,7 @@ static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[], ...@@ -1602,7 +1609,7 @@ static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[],
} else } else
t = netdev_priv(dev); t = netdev_priv(dev);
ipip6_tunnel_update(t, &p); ipip6_tunnel_update(t, &p, fwmark);
#ifdef CONFIG_IPV6_SIT_6RD #ifdef CONFIG_IPV6_SIT_6RD
if (ipip6_netlink_6rd_parms(data, &ip6rd)) if (ipip6_netlink_6rd_parms(data, &ip6rd))
...@@ -1649,6 +1656,8 @@ static size_t ipip6_get_size(const struct net_device *dev) ...@@ -1649,6 +1656,8 @@ static size_t ipip6_get_size(const struct net_device *dev)
nla_total_size(2) + nla_total_size(2) +
/* IFLA_IPTUN_ENCAP_DPORT */ /* IFLA_IPTUN_ENCAP_DPORT */
nla_total_size(2) + nla_total_size(2) +
/* IFLA_IPTUN_FWMARK */
nla_total_size(4) +
0; 0;
} }
...@@ -1665,7 +1674,8 @@ static int ipip6_fill_info(struct sk_buff *skb, const struct net_device *dev) ...@@ -1665,7 +1674,8 @@ static int ipip6_fill_info(struct sk_buff *skb, const struct net_device *dev)
nla_put_u8(skb, IFLA_IPTUN_PMTUDISC, nla_put_u8(skb, IFLA_IPTUN_PMTUDISC,
!!(parm->iph.frag_off & htons(IP_DF))) || !!(parm->iph.frag_off & htons(IP_DF))) ||
nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->iph.protocol) || nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->iph.protocol) ||
nla_put_be16(skb, IFLA_IPTUN_FLAGS, parm->i_flags)) nla_put_be16(skb, IFLA_IPTUN_FLAGS, parm->i_flags) ||
nla_put_u32(skb, IFLA_IPTUN_FWMARK, tunnel->fwmark))
goto nla_put_failure; goto nla_put_failure;
#ifdef CONFIG_IPV6_SIT_6RD #ifdef CONFIG_IPV6_SIT_6RD
...@@ -1715,6 +1725,7 @@ static const struct nla_policy ipip6_policy[IFLA_IPTUN_MAX + 1] = { ...@@ -1715,6 +1725,7 @@ static const struct nla_policy ipip6_policy[IFLA_IPTUN_MAX + 1] = {
[IFLA_IPTUN_ENCAP_FLAGS] = { .type = NLA_U16 }, [IFLA_IPTUN_ENCAP_FLAGS] = { .type = NLA_U16 },
[IFLA_IPTUN_ENCAP_SPORT] = { .type = NLA_U16 }, [IFLA_IPTUN_ENCAP_SPORT] = { .type = NLA_U16 },
[IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 }, [IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 },
[IFLA_IPTUN_FWMARK] = { .type = NLA_U32 },
}; };
static void ipip6_dellink(struct net_device *dev, struct list_head *head) static void ipip6_dellink(struct net_device *dev, struct list_head *head)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment