mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-02-16 17:45:01 -05:00
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:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -3,3 +3,4 @@ CONFIG_NET_SCH_NETEM=m
|
||||
CONFIG_HSR=y
|
||||
CONFIG_VETH=y
|
||||
CONFIG_BRIDGE=y
|
||||
CONFIG_VLAN_8021Q=m
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user