diff --git a/drivers/net/amt.c b/drivers/net/amt.c
index 377660e55..58e9da443 100644
--- a/drivers/net/amt.c
+++ b/drivers/net/amt.c
@@ -5719,6 +5719,7 @@ static const struct nla_policy amt_policy[IFLA_AMT_MAX + 1] = {
[IFLA_AMT_NUM_QUEUES] = NLA_POLICY_MAX(NLA_U32, AMT_MAX_QUEUES),
[IFLA_AMT_DISCOVERY_IP6] = NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)),
[IFLA_AMT_REMOTE_IP6] = NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)),
+ [IFLA_AMT_OFFLOAD_MODE] = { .type = NLA_U32 },
};
static int amt_validate(struct nlattr *tb[], struct nlattr *data[],@@ -5745,6 +5746,22 @@ static int amt_validate(struct nlattr *tb[], struct nlattr *data[],
return -EINVAL;
}
+ if (data[IFLA_AMT_OFFLOAD_MODE]) {
+ u32 offload = nla_get_u32(data[IFLA_AMT_OFFLOAD_MODE]);
+
+ if (offload > AMT_OFFLOAD_MODE_MAX) {
+ NL_SET_ERR_MSG_ATTR(extack, data[IFLA_AMT_OFFLOAD_MODE],
+ "Offload mode is not valid");
+ return -EINVAL;
+ }
+ if (offload != AMT_OFFLOAD_MODE_SOFTWARE &&
+ nla_get_u32(data[IFLA_AMT_MODE]) != AMT_MODE_RELAY) {
+ NL_SET_ERR_MSG_ATTR(extack, data[IFLA_AMT_OFFLOAD_MODE],
+ "Offload is only valid in relay mode");
+ return -EINVAL;
+ }
+ }
+
if (!data[IFLA_AMT_LOCAL_IP] && !data[IFLA_AMT_LOCAL_IP6]) {
NL_SET_ERR_MSG_MOD(extack,
"Local IPv4 or IPv6 attribute is required");@@ -5802,6 +5819,9 @@ static int amt_newlink(struct net_device *dev,
amt->net = link_net;
amt->mode = nla_get_u32(data[IFLA_AMT_MODE]);
+ amt->offload_mode = data[IFLA_AMT_OFFLOAD_MODE] ?
+ nla_get_u32(data[IFLA_AMT_OFFLOAD_MODE]) :
+ AMT_OFFLOAD_MODE_SOFTWARE;
if (data[IFLA_AMT_MAX_TUNNELS] &&
nla_get_u32(data[IFLA_AMT_MAX_TUNNELS]))
@@ -5998,7 +6018,8 @@ static size_t amt_get_size(const struct net_device *dev)
nla_total_size(sizeof(struct iphdr)) + /* IFLA_AMT_LOCAL_IP */
nla_total_size(sizeof(struct in6_addr)) + /* IFLA_AMT_LOCAL_IP6 */
nla_total_size(sizeof(struct in6_addr)) + /* IFLA_AMT_DISCOVERY_IP6 */
- nla_total_size(sizeof(struct in6_addr)); /* IFLA_AMT_REMOTE_IP6 */
+ nla_total_size(sizeof(struct in6_addr)) + /* IFLA_AMT_REMOTE_IP6 */
+ nla_total_size(sizeof(__u32)); /* IFLA_AMT_OFFLOAD_MODE */
}
static int amt_fill_info(struct sk_buff *skb, const struct net_device *dev)
@@ -6068,6 +6089,8 @@ static int amt_fill_info(struct sk_buff *skb, const struct net_device *dev)
goto nla_put_failure;
if (nla_put_u32(skb, IFLA_AMT_NUM_QUEUES, dev->real_num_tx_queues))
goto nla_put_failure;
+ if (nla_put_u32(skb, IFLA_AMT_OFFLOAD_MODE, amt->offload_mode))
+ goto nla_put_failure;
return 0;
diff --git a/include/uapi/linux/amt.h b/include/uapi/linux/amt.h
index de1ae1929..c67a1f763 100644
--- a/include/uapi/linux/amt.h
+++ b/include/uapi/linux/amt.h
@@ -122,6 +122,13 @@ enum {
* AMT_MAX_TUNNELS_PER_SOURCE; raise it on a relay that fronts CGNAT.
*/
IFLA_AMT_MAX_TUNNELS_PER_SOURCE,
+ /* Relay mode: enum ifla_amt_offload_mode, default
+ * AMT_OFFLOAD_MODE_SOFTWARE. Replication offload to a provider
+ * registered on the IFLA_AMT_LINK device (include/net/amt_offload.h).
+ * Required mode refuses creation with -ENODEV when no usable provider
+ * is bound. Gateway mode accepts software only.
+ */
+ IFLA_AMT_OFFLOAD_MODE,
__IFLA_AMT_MAX,
};
--
2.43.0