Merge branch 'introduce-vlan-support-in-hsr'

MD Danish Anwar says:

====================
Introduce VLAN support in HSR

This series adds VLAN support to HSR framework.
This series also adds VLAN support to HSR mode of ICSSG Ethernet driver.

[1] 9cfb5f8bd1/hsr_vlan_logs
v1 https://lore.kernel.org/all/20241004074715.791191-1-danishanwar@ti.com/
v2 https://lore.kernel.org/all/20241024103056.3201071-1-danishanwar@ti.com/
====================

Link: https://patch.msgid.link/20241106091710.3308519-1-danishanwar@ti.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski
2024-11-11 16:40:47 -08:00
5 changed files with 236 additions and 12 deletions

View File

@@ -808,6 +808,47 @@ static netdev_features_t emac_ndo_fix_features(struct net_device *ndev,
return features;
}
static int emac_ndo_vlan_rx_add_vid(struct net_device *ndev,
__be16 proto, u16 vid)
{
struct prueth_emac *emac = netdev_priv(ndev);
struct prueth *prueth = emac->prueth;
int untag_mask = 0;
int port_mask;
if (prueth->is_hsr_offload_mode) {
port_mask = BIT(PRUETH_PORT_HOST) | BIT(emac->port_id);
untag_mask = 0;
netdev_dbg(emac->ndev, "VID add vid:%u port_mask:%X untag_mask %X\n",
vid, port_mask, untag_mask);
icssg_vtbl_modify(emac, vid, port_mask, untag_mask, true);
icssg_set_pvid(emac->prueth, vid, emac->port_id);
}
return 0;
}
static int emac_ndo_vlan_rx_del_vid(struct net_device *ndev,
__be16 proto, u16 vid)
{
struct prueth_emac *emac = netdev_priv(ndev);
struct prueth *prueth = emac->prueth;
int untag_mask = 0;
int port_mask;
if (prueth->is_hsr_offload_mode) {
port_mask = BIT(PRUETH_PORT_HOST);
untag_mask = 0;
netdev_dbg(emac->ndev, "VID del vid:%u port_mask:%X untag_mask %X\n",
vid, port_mask, untag_mask);
icssg_vtbl_modify(emac, vid, port_mask, untag_mask, false);
}
return 0;
}
static const struct net_device_ops emac_netdev_ops = {
.ndo_open = emac_ndo_open,
.ndo_stop = emac_ndo_stop,
@@ -820,6 +861,8 @@ static const struct net_device_ops emac_netdev_ops = {
.ndo_get_stats64 = icssg_ndo_get_stats64,
.ndo_get_phys_port_name = icssg_ndo_get_phys_port_name,
.ndo_fix_features = emac_ndo_fix_features,
.ndo_vlan_rx_add_vid = emac_ndo_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = emac_ndo_vlan_rx_del_vid,
};
static int prueth_netdev_init(struct prueth *prueth,
@@ -947,7 +990,7 @@ static int prueth_netdev_init(struct prueth *prueth,
ndev->netdev_ops = &emac_netdev_ops;
ndev->ethtool_ops = &icssg_ethtool_ops;
ndev->hw_features = NETIF_F_SG;
ndev->features = ndev->hw_features;
ndev->features = ndev->hw_features | NETIF_F_HW_VLAN_CTAG_FILTER;
ndev->hw_features |= NETIF_PRUETH_HSR_OFFLOAD_FEATURES;
netif_napi_add(ndev, &emac->napi_rx, icssg_napi_rx_poll);

View File

@@ -515,6 +515,77 @@ static void hsr_change_rx_flags(struct net_device *dev, int change)
}
}
static int hsr_ndo_vlan_rx_add_vid(struct net_device *dev,
__be16 proto, u16 vid)
{
bool is_slave_a_added = false;
bool is_slave_b_added = false;
struct hsr_port *port;
struct hsr_priv *hsr;
int ret = 0;
hsr = netdev_priv(dev);
hsr_for_each_port(hsr, port) {
if (port->type == HSR_PT_MASTER ||
port->type == HSR_PT_INTERLINK)
continue;
ret = vlan_vid_add(port->dev, proto, vid);
switch (port->type) {
case HSR_PT_SLAVE_A:
if (ret) {
/* clean up Slave-B */
netdev_err(dev, "add vid failed for Slave-A\n");
if (is_slave_b_added)
vlan_vid_del(port->dev, proto, vid);
return ret;
}
is_slave_a_added = true;
break;
case HSR_PT_SLAVE_B:
if (ret) {
/* clean up Slave-A */
netdev_err(dev, "add vid failed for Slave-B\n");
if (is_slave_a_added)
vlan_vid_del(port->dev, proto, vid);
return ret;
}
is_slave_b_added = true;
break;
default:
break;
}
}
return 0;
}
static int hsr_ndo_vlan_rx_kill_vid(struct net_device *dev,
__be16 proto, u16 vid)
{
struct hsr_port *port;
struct hsr_priv *hsr;
hsr = netdev_priv(dev);
hsr_for_each_port(hsr, port) {
switch (port->type) {
case HSR_PT_SLAVE_A:
case HSR_PT_SLAVE_B:
vlan_vid_del(port->dev, proto, vid);
break;
default:
break;
}
}
return 0;
}
static const struct net_device_ops hsr_device_ops = {
.ndo_change_mtu = hsr_dev_change_mtu,
.ndo_open = hsr_dev_open,
@@ -523,6 +594,8 @@ static const struct net_device_ops hsr_device_ops = {
.ndo_change_rx_flags = hsr_change_rx_flags,
.ndo_fix_features = hsr_fix_features,
.ndo_set_rx_mode = hsr_set_rx_mode,
.ndo_vlan_rx_add_vid = hsr_ndo_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = hsr_ndo_vlan_rx_kill_vid,
};
static const struct device_type hsr_type = {
@@ -569,14 +642,10 @@ void hsr_dev_setup(struct net_device *dev)
dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
NETIF_F_GSO_MASK | NETIF_F_HW_CSUM |
NETIF_F_HW_VLAN_CTAG_TX;
NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_HW_VLAN_CTAG_FILTER;
dev->features = dev->hw_features;
/* VLAN on top of HSR needs testing and probably some work on
* hsr_header_create() etc.
*/
dev->features |= NETIF_F_VLAN_CHALLENGED;
}
/* Return true if dev is a HSR master; return false otherwise.
@@ -652,6 +721,10 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
(slave[1]->features & NETIF_F_HW_HSR_FWD))
hsr->fwd_offloaded = true;
if ((slave[0]->features & NETIF_F_HW_VLAN_CTAG_FILTER) &&
(slave[1]->features & NETIF_F_HW_VLAN_CTAG_FILTER))
hsr_dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
res = register_netdevice(hsr_dev);
if (res)
goto err_unregister;

View File

@@ -280,6 +280,7 @@ static struct sk_buff *hsr_fill_tag(struct sk_buff *skb,
struct hsr_port *port, u8 proto_version)
{
struct hsr_ethhdr *hsr_ethhdr;
unsigned char *pc;
int lsdu_size;
/* pad to minimum packet size which is 60 + 6 (HSR tag) */
@@ -290,7 +291,18 @@ static struct sk_buff *hsr_fill_tag(struct sk_buff *skb,
if (frame->is_vlan)
lsdu_size -= 4;
hsr_ethhdr = (struct hsr_ethhdr *)skb_mac_header(skb);
pc = skb_mac_header(skb);
if (frame->is_vlan)
/* This 4-byte shift (size of a vlan tag) does not
* mean that the ethhdr starts there. But rather it
* provides the proper environment for accessing
* the fields, such as hsr_tag etc., just like
* when the vlan tag is not there. This is because
* the hsr tag is after the vlan tag.
*/
hsr_ethhdr = (struct hsr_ethhdr *)(pc + VLAN_HLEN);
else
hsr_ethhdr = (struct hsr_ethhdr *)pc;
hsr_set_path_id(hsr_ethhdr, port);
set_hsr_tag_LSDU_size(&hsr_ethhdr->hsr_tag, lsdu_size);
@@ -368,7 +380,7 @@ struct sk_buff *prp_create_tagged_frame(struct hsr_frame_info *frame,
return skb_clone(frame->skb_std, GFP_ATOMIC);
}
skb = skb_copy_expand(frame->skb_std, 0,
skb = skb_copy_expand(frame->skb_std, skb_headroom(frame->skb_std),
skb_tailroom(frame->skb_std) + HSR_HLEN,
GFP_ATOMIC);
return prp_fill_rct(skb, frame, port);
@@ -690,9 +702,6 @@ static int fill_frame_info(struct hsr_frame_info *frame,
if (frame->is_vlan) {
vlan_hdr = (struct hsr_vlan_ethhdr *)ethhdr;
proto = vlan_hdr->vlanhdr.h_vlan_encapsulated_proto;
/* FIXME: */
netdev_warn_once(skb->dev, "VLAN not yet supported");
return -EINVAL;
}
frame->is_from_san = false;

View File

@@ -3,3 +3,4 @@ CONFIG_NET_SCH_NETEM=m
CONFIG_HSR=y
CONFIG_VETH=y
CONFIG_BRIDGE=y
CONFIG_VLAN_8021Q=m

View File

@@ -175,6 +175,100 @@ setup_hsr_interfaces()
ip -net "$ns3" link set hsr3 up
}
setup_vlan_interfaces() {
ip -net "$ns1" link add link hsr1 name hsr1.2 type vlan id 2
ip -net "$ns1" link add link hsr1 name hsr1.3 type vlan id 3
ip -net "$ns1" link add link hsr1 name hsr1.4 type vlan id 4
ip -net "$ns1" link add link hsr1 name hsr1.5 type vlan id 5
ip -net "$ns2" link add link hsr2 name hsr2.2 type vlan id 2
ip -net "$ns2" link add link hsr2 name hsr2.3 type vlan id 3
ip -net "$ns2" link add link hsr2 name hsr2.4 type vlan id 4
ip -net "$ns2" link add link hsr2 name hsr2.5 type vlan id 5
ip -net "$ns3" link add link hsr3 name hsr3.2 type vlan id 2
ip -net "$ns3" link add link hsr3 name hsr3.3 type vlan id 3
ip -net "$ns3" link add link hsr3 name hsr3.4 type vlan id 4
ip -net "$ns3" link add link hsr3 name hsr3.5 type vlan id 5
ip -net "$ns1" addr add 100.64.2.1/24 dev hsr1.2
ip -net "$ns1" addr add 100.64.3.1/24 dev hsr1.3
ip -net "$ns1" addr add 100.64.4.1/24 dev hsr1.4
ip -net "$ns1" addr add 100.64.5.1/24 dev hsr1.5
ip -net "$ns2" addr add 100.64.2.2/24 dev hsr2.2
ip -net "$ns2" addr add 100.64.3.2/24 dev hsr2.3
ip -net "$ns2" addr add 100.64.4.2/24 dev hsr2.4
ip -net "$ns2" addr add 100.64.5.2/24 dev hsr2.5
ip -net "$ns3" addr add 100.64.2.3/24 dev hsr3.2
ip -net "$ns3" addr add 100.64.3.3/24 dev hsr3.3
ip -net "$ns3" addr add 100.64.4.3/24 dev hsr3.4
ip -net "$ns3" addr add 100.64.5.3/24 dev hsr3.5
ip -net "$ns1" link set dev hsr1.2 up
ip -net "$ns1" link set dev hsr1.3 up
ip -net "$ns1" link set dev hsr1.4 up
ip -net "$ns1" link set dev hsr1.5 up
ip -net "$ns2" link set dev hsr2.2 up
ip -net "$ns2" link set dev hsr2.3 up
ip -net "$ns2" link set dev hsr2.4 up
ip -net "$ns2" link set dev hsr2.5 up
ip -net "$ns3" link set dev hsr3.2 up
ip -net "$ns3" link set dev hsr3.3 up
ip -net "$ns3" link set dev hsr3.4 up
ip -net "$ns3" link set dev hsr3.5 up
}
hsr_vlan_ping() {
do_ping "$ns1" 100.64.2.2
do_ping "$ns1" 100.64.3.2
do_ping "$ns1" 100.64.4.2
do_ping "$ns1" 100.64.5.2
do_ping "$ns1" 100.64.2.3
do_ping "$ns1" 100.64.3.3
do_ping "$ns1" 100.64.4.3
do_ping "$ns1" 100.64.5.3
do_ping "$ns2" 100.64.2.1
do_ping "$ns2" 100.64.3.1
do_ping "$ns2" 100.64.4.1
do_ping "$ns2" 100.64.5.1
do_ping "$ns2" 100.64.2.3
do_ping "$ns2" 100.64.3.3
do_ping "$ns2" 100.64.4.3
do_ping "$ns2" 100.64.5.3
do_ping "$ns3" 100.64.2.1
do_ping "$ns3" 100.64.3.1
do_ping "$ns3" 100.64.4.1
do_ping "$ns3" 100.64.5.1
do_ping "$ns3" 100.64.2.2
do_ping "$ns3" 100.64.3.2
do_ping "$ns3" 100.64.4.2
do_ping "$ns3" 100.64.5.2
}
run_vlan_tests() {
vlan_challenged_hsr1=$(ip net exec "$ns1" ethtool -k hsr1 | grep "vlan-challenged" | awk '{print $2}')
vlan_challenged_hsr2=$(ip net exec "$ns2" ethtool -k hsr2 | grep "vlan-challenged" | awk '{print $2}')
vlan_challenged_hsr3=$(ip net exec "$ns3" ethtool -k hsr3 | grep "vlan-challenged" | awk '{print $2}')
if [[ "$vlan_challenged_hsr1" = "off" || "$vlan_challenged_hsr2" = "off" || "$vlan_challenged_hsr3" = "off" ]]; then
echo "INFO: Running VLAN tests"
setup_vlan_interfaces
hsr_vlan_ping
else
echo "INFO: Not Running VLAN tests as the device does not support VLAN"
fi
}
check_prerequisites
setup_ns ns1 ns2 ns3
@@ -183,9 +277,13 @@ trap cleanup_all_ns EXIT
setup_hsr_interfaces 0
do_complete_ping_test
run_vlan_tests
setup_ns ns1 ns2 ns3
setup_hsr_interfaces 1
do_complete_ping_test
run_vlan_tests
exit $ret