|
@@ -841,17 +841,19 @@ out:
|
|
|
return ipgre_tunnel_validate(tb, data);
|
|
|
}
|
|
|
|
|
|
-static void ipgre_netlink_parms(struct net_device *dev,
|
|
|
+static int ipgre_netlink_parms(struct net_device *dev,
|
|
|
struct nlattr *data[],
|
|
|
struct nlattr *tb[],
|
|
|
struct ip_tunnel_parm *parms)
|
|
|
{
|
|
|
+ struct ip_tunnel *t = netdev_priv(dev);
|
|
|
+
|
|
|
memset(parms, 0, sizeof(*parms));
|
|
|
|
|
|
parms->iph.protocol = IPPROTO_GRE;
|
|
|
|
|
|
if (!data)
|
|
|
- return;
|
|
|
+ return 0;
|
|
|
|
|
|
if (data[IFLA_GRE_LINK])
|
|
|
parms->link = nla_get_u32(data[IFLA_GRE_LINK]);
|
|
@@ -880,16 +882,26 @@ static void ipgre_netlink_parms(struct net_device *dev,
|
|
|
if (data[IFLA_GRE_TOS])
|
|
|
parms->iph.tos = nla_get_u8(data[IFLA_GRE_TOS]);
|
|
|
|
|
|
- if (!data[IFLA_GRE_PMTUDISC] || nla_get_u8(data[IFLA_GRE_PMTUDISC]))
|
|
|
+ if (!data[IFLA_GRE_PMTUDISC] || nla_get_u8(data[IFLA_GRE_PMTUDISC])) {
|
|
|
+ if (t->ignore_df)
|
|
|
+ return -EINVAL;
|
|
|
parms->iph.frag_off = htons(IP_DF);
|
|
|
+ }
|
|
|
|
|
|
if (data[IFLA_GRE_COLLECT_METADATA]) {
|
|
|
- struct ip_tunnel *t = netdev_priv(dev);
|
|
|
-
|
|
|
t->collect_md = true;
|
|
|
if (dev->type == ARPHRD_IPGRE)
|
|
|
dev->type = ARPHRD_NONE;
|
|
|
}
|
|
|
+
|
|
|
+ if (data[IFLA_GRE_IGNORE_DF]) {
|
|
|
+ if (nla_get_u8(data[IFLA_GRE_IGNORE_DF])
|
|
|
+ && (parms->iph.frag_off & htons(IP_DF)))
|
|
|
+ return -EINVAL;
|
|
|
+ t->ignore_df = !!nla_get_u8(data[IFLA_GRE_IGNORE_DF]);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
/* This function returns true when ENCAP attributes are present in the nl msg */
|
|
@@ -960,16 +972,19 @@ static int ipgre_newlink(struct net *src_net, struct net_device *dev,
|
|
|
{
|
|
|
struct ip_tunnel_parm p;
|
|
|
struct ip_tunnel_encap ipencap;
|
|
|
+ int err;
|
|
|
|
|
|
if (ipgre_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;
|
|
|
}
|
|
|
|
|
|
- ipgre_netlink_parms(dev, data, tb, &p);
|
|
|
+ err = ipgre_netlink_parms(dev, data, tb, &p);
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
return ip_tunnel_newlink(dev, tb, &p);
|
|
|
}
|
|
|
|
|
@@ -978,16 +993,19 @@ static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
|
|
|
{
|
|
|
struct ip_tunnel_parm p;
|
|
|
struct ip_tunnel_encap ipencap;
|
|
|
+ int err;
|
|
|
|
|
|
if (ipgre_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;
|
|
|
}
|
|
|
|
|
|
- ipgre_netlink_parms(dev, data, tb, &p);
|
|
|
+ err = ipgre_netlink_parms(dev, data, tb, &p);
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
return ip_tunnel_changelink(dev, tb, &p);
|
|
|
}
|
|
|
|
|
@@ -1024,6 +1042,8 @@ static size_t ipgre_get_size(const struct net_device *dev)
|
|
|
nla_total_size(2) +
|
|
|
/* IFLA_GRE_COLLECT_METADATA */
|
|
|
nla_total_size(0) +
|
|
|
+ /* IFLA_GRE_IGNORE_DF */
|
|
|
+ nla_total_size(1) +
|
|
|
0;
|
|
|
}
|
|
|
|
|
@@ -1057,6 +1077,9 @@ static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
|
|
|
t->encap.flags))
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
+ if (nla_put_u8(skb, IFLA_GRE_IGNORE_DF, t->ignore_df))
|
|
|
+ goto nla_put_failure;
|
|
|
+
|
|
|
if (t->collect_md) {
|
|
|
if (nla_put_flag(skb, IFLA_GRE_COLLECT_METADATA))
|
|
|
goto nla_put_failure;
|
|
@@ -1084,6 +1107,7 @@ static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = {
|
|
|
[IFLA_GRE_ENCAP_SPORT] = { .type = NLA_U16 },
|
|
|
[IFLA_GRE_ENCAP_DPORT] = { .type = NLA_U16 },
|
|
|
[IFLA_GRE_COLLECT_METADATA] = { .type = NLA_FLAG },
|
|
|
+ [IFLA_GRE_IGNORE_DF] = { .type = NLA_U8 },
|
|
|
};
|
|
|
|
|
|
static struct rtnl_link_ops ipgre_link_ops __read_mostly = {
|