|
@@ -3136,6 +3136,8 @@ static int rocker_port_vlan_flood_group(struct rocker_port *rocker_port,
|
|
|
|
|
|
for (i = 0; i < rocker->port_count; i++) {
|
|
for (i = 0; i < rocker->port_count; i++) {
|
|
p = rocker->ports[i];
|
|
p = rocker->ports[i];
|
|
|
|
+ if (!p)
|
|
|
|
+ continue;
|
|
if (!rocker_port_is_bridged(p))
|
|
if (!rocker_port_is_bridged(p))
|
|
continue;
|
|
continue;
|
|
if (test_bit(ntohs(vlan_id), p->vlan_bitmap)) {
|
|
if (test_bit(ntohs(vlan_id), p->vlan_bitmap)) {
|
|
@@ -3195,7 +3197,7 @@ static int rocker_port_vlan_l2_groups(struct rocker_port *rocker_port,
|
|
|
|
|
|
for (i = 0; i < rocker->port_count; i++) {
|
|
for (i = 0; i < rocker->port_count; i++) {
|
|
p = rocker->ports[i];
|
|
p = rocker->ports[i];
|
|
- if (test_bit(ntohs(vlan_id), p->vlan_bitmap))
|
|
|
|
|
|
+ if (p && test_bit(ntohs(vlan_id), p->vlan_bitmap))
|
|
ref++;
|
|
ref++;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -4162,35 +4164,6 @@ static int rocker_port_set_mac_address(struct net_device *dev, void *p)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static int rocker_port_vlan_rx_add_vid(struct net_device *dev,
|
|
|
|
- __be16 proto, u16 vid)
|
|
|
|
-{
|
|
|
|
- struct rocker_port *rocker_port = netdev_priv(dev);
|
|
|
|
- int err;
|
|
|
|
-
|
|
|
|
- err = rocker_port_vlan(rocker_port, SWITCHDEV_TRANS_NONE, 0, vid);
|
|
|
|
- if (err)
|
|
|
|
- return err;
|
|
|
|
-
|
|
|
|
- return rocker_port_router_mac(rocker_port, SWITCHDEV_TRANS_NONE,
|
|
|
|
- 0, htons(vid));
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int rocker_port_vlan_rx_kill_vid(struct net_device *dev,
|
|
|
|
- __be16 proto, u16 vid)
|
|
|
|
-{
|
|
|
|
- struct rocker_port *rocker_port = netdev_priv(dev);
|
|
|
|
- int err;
|
|
|
|
-
|
|
|
|
- err = rocker_port_router_mac(rocker_port, SWITCHDEV_TRANS_NONE,
|
|
|
|
- ROCKER_OP_FLAG_REMOVE, htons(vid));
|
|
|
|
- if (err)
|
|
|
|
- return err;
|
|
|
|
-
|
|
|
|
- return rocker_port_vlan(rocker_port, SWITCHDEV_TRANS_NONE,
|
|
|
|
- ROCKER_OP_FLAG_REMOVE, vid);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static int rocker_port_get_phys_port_name(struct net_device *dev,
|
|
static int rocker_port_get_phys_port_name(struct net_device *dev,
|
|
char *buf, size_t len)
|
|
char *buf, size_t len)
|
|
{
|
|
{
|
|
@@ -4211,8 +4184,6 @@ static const struct net_device_ops rocker_port_netdev_ops = {
|
|
.ndo_stop = rocker_port_stop,
|
|
.ndo_stop = rocker_port_stop,
|
|
.ndo_start_xmit = rocker_port_xmit,
|
|
.ndo_start_xmit = rocker_port_xmit,
|
|
.ndo_set_mac_address = rocker_port_set_mac_address,
|
|
.ndo_set_mac_address = rocker_port_set_mac_address,
|
|
- .ndo_vlan_rx_add_vid = rocker_port_vlan_rx_add_vid,
|
|
|
|
- .ndo_vlan_rx_kill_vid = rocker_port_vlan_rx_kill_vid,
|
|
|
|
.ndo_bridge_getlink = switchdev_port_bridge_getlink,
|
|
.ndo_bridge_getlink = switchdev_port_bridge_getlink,
|
|
.ndo_bridge_setlink = switchdev_port_bridge_setlink,
|
|
.ndo_bridge_setlink = switchdev_port_bridge_setlink,
|
|
.ndo_bridge_dellink = switchdev_port_bridge_dellink,
|
|
.ndo_bridge_dellink = switchdev_port_bridge_dellink,
|
|
@@ -4320,7 +4291,12 @@ static int rocker_port_vlan_add(struct rocker_port *rocker_port,
|
|
if (err)
|
|
if (err)
|
|
return err;
|
|
return err;
|
|
|
|
|
|
- return rocker_port_router_mac(rocker_port, trans, 0, htons(vid));
|
|
|
|
|
|
+ err = rocker_port_router_mac(rocker_port, trans, 0, htons(vid));
|
|
|
|
+ if (err)
|
|
|
|
+ rocker_port_vlan(rocker_port, trans,
|
|
|
|
+ ROCKER_OP_FLAG_REMOVE, vid);
|
|
|
|
+
|
|
|
|
+ return err;
|
|
}
|
|
}
|
|
|
|
|
|
static int rocker_port_vlans_add(struct rocker_port *rocker_port,
|
|
static int rocker_port_vlans_add(struct rocker_port *rocker_port,
|
|
@@ -4852,6 +4828,7 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
|
|
const struct pci_dev *pdev = rocker->pdev;
|
|
const struct pci_dev *pdev = rocker->pdev;
|
|
struct rocker_port *rocker_port;
|
|
struct rocker_port *rocker_port;
|
|
struct net_device *dev;
|
|
struct net_device *dev;
|
|
|
|
+ u16 untagged_vid = 0;
|
|
int err;
|
|
int err;
|
|
|
|
|
|
dev = alloc_etherdev(sizeof(struct rocker_port));
|
|
dev = alloc_etherdev(sizeof(struct rocker_port));
|
|
@@ -4875,8 +4852,7 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
|
|
NAPI_POLL_WEIGHT);
|
|
NAPI_POLL_WEIGHT);
|
|
rocker_carrier_init(rocker_port);
|
|
rocker_carrier_init(rocker_port);
|
|
|
|
|
|
- dev->features |= NETIF_F_NETNS_LOCAL |
|
|
|
|
- NETIF_F_HW_VLAN_CTAG_FILTER;
|
|
|
|
|
|
+ dev->features |= NETIF_F_NETNS_LOCAL;
|
|
|
|
|
|
err = register_netdev(dev);
|
|
err = register_netdev(dev);
|
|
if (err) {
|
|
if (err) {
|
|
@@ -4887,16 +4863,27 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
|
|
|
|
|
|
rocker_port_set_learning(rocker_port, SWITCHDEV_TRANS_NONE);
|
|
rocker_port_set_learning(rocker_port, SWITCHDEV_TRANS_NONE);
|
|
|
|
|
|
- rocker_port->internal_vlan_id =
|
|
|
|
- rocker_port_internal_vlan_id_get(rocker_port, dev->ifindex);
|
|
|
|
err = rocker_port_ig_tbl(rocker_port, SWITCHDEV_TRANS_NONE, 0);
|
|
err = rocker_port_ig_tbl(rocker_port, SWITCHDEV_TRANS_NONE, 0);
|
|
if (err) {
|
|
if (err) {
|
|
dev_err(&pdev->dev, "install ig port table failed\n");
|
|
dev_err(&pdev->dev, "install ig port table failed\n");
|
|
goto err_port_ig_tbl;
|
|
goto err_port_ig_tbl;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ rocker_port->internal_vlan_id =
|
|
|
|
+ rocker_port_internal_vlan_id_get(rocker_port, dev->ifindex);
|
|
|
|
+
|
|
|
|
+ err = rocker_port_vlan_add(rocker_port, SWITCHDEV_TRANS_NONE,
|
|
|
|
+ untagged_vid, 0);
|
|
|
|
+ if (err) {
|
|
|
|
+ netdev_err(rocker_port->dev, "install untagged VLAN failed\n");
|
|
|
|
+ goto err_untagged_vlan;
|
|
|
|
+ }
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
|
|
+err_untagged_vlan:
|
|
|
|
+ rocker_port_ig_tbl(rocker_port, SWITCHDEV_TRANS_NONE,
|
|
|
|
+ ROCKER_OP_FLAG_REMOVE);
|
|
err_port_ig_tbl:
|
|
err_port_ig_tbl:
|
|
unregister_netdev(dev);
|
|
unregister_netdev(dev);
|
|
err_register_netdev:
|
|
err_register_netdev:
|
|
@@ -4911,7 +4898,7 @@ static int rocker_probe_ports(struct rocker *rocker)
|
|
int err;
|
|
int err;
|
|
|
|
|
|
alloc_size = sizeof(struct rocker_port *) * rocker->port_count;
|
|
alloc_size = sizeof(struct rocker_port *) * rocker->port_count;
|
|
- rocker->ports = kmalloc(alloc_size, GFP_KERNEL);
|
|
|
|
|
|
+ rocker->ports = kzalloc(alloc_size, GFP_KERNEL);
|
|
if (!rocker->ports)
|
|
if (!rocker->ports)
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
for (i = 0; i < rocker->port_count; i++) {
|
|
for (i = 0; i < rocker->port_count; i++) {
|
|
@@ -5134,41 +5121,49 @@ static bool rocker_port_dev_check(const struct net_device *dev)
|
|
static int rocker_port_bridge_join(struct rocker_port *rocker_port,
|
|
static int rocker_port_bridge_join(struct rocker_port *rocker_port,
|
|
struct net_device *bridge)
|
|
struct net_device *bridge)
|
|
{
|
|
{
|
|
|
|
+ u16 untagged_vid = 0;
|
|
int err;
|
|
int err;
|
|
|
|
|
|
- rocker_port_internal_vlan_id_put(rocker_port,
|
|
|
|
- rocker_port->dev->ifindex);
|
|
|
|
-
|
|
|
|
- rocker_port->bridge_dev = bridge;
|
|
|
|
|
|
+ /* Port is joining bridge, so the internal VLAN for the
|
|
|
|
+ * port is going to change to the bridge internal VLAN.
|
|
|
|
+ * Let's remove untagged VLAN (vid=0) from port and
|
|
|
|
+ * re-add once internal VLAN has changed.
|
|
|
|
+ */
|
|
|
|
|
|
- /* Use bridge internal VLAN ID for untagged pkts */
|
|
|
|
- err = rocker_port_vlan(rocker_port, SWITCHDEV_TRANS_NONE,
|
|
|
|
- ROCKER_OP_FLAG_REMOVE, 0);
|
|
|
|
|
|
+ err = rocker_port_vlan_del(rocker_port, untagged_vid, 0);
|
|
if (err)
|
|
if (err)
|
|
return err;
|
|
return err;
|
|
|
|
+
|
|
|
|
+ rocker_port_internal_vlan_id_put(rocker_port,
|
|
|
|
+ rocker_port->dev->ifindex);
|
|
rocker_port->internal_vlan_id =
|
|
rocker_port->internal_vlan_id =
|
|
rocker_port_internal_vlan_id_get(rocker_port, bridge->ifindex);
|
|
rocker_port_internal_vlan_id_get(rocker_port, bridge->ifindex);
|
|
- return rocker_port_vlan(rocker_port, SWITCHDEV_TRANS_NONE, 0, 0);
|
|
|
|
|
|
+
|
|
|
|
+ rocker_port->bridge_dev = bridge;
|
|
|
|
+
|
|
|
|
+ return rocker_port_vlan_add(rocker_port, SWITCHDEV_TRANS_NONE,
|
|
|
|
+ untagged_vid, 0);
|
|
}
|
|
}
|
|
|
|
|
|
static int rocker_port_bridge_leave(struct rocker_port *rocker_port)
|
|
static int rocker_port_bridge_leave(struct rocker_port *rocker_port)
|
|
{
|
|
{
|
|
|
|
+ u16 untagged_vid = 0;
|
|
int err;
|
|
int err;
|
|
|
|
|
|
- rocker_port_internal_vlan_id_put(rocker_port,
|
|
|
|
- rocker_port->bridge_dev->ifindex);
|
|
|
|
-
|
|
|
|
- rocker_port->bridge_dev = NULL;
|
|
|
|
-
|
|
|
|
- /* Use port internal VLAN ID for untagged pkts */
|
|
|
|
- err = rocker_port_vlan(rocker_port, SWITCHDEV_TRANS_NONE,
|
|
|
|
- ROCKER_OP_FLAG_REMOVE, 0);
|
|
|
|
|
|
+ err = rocker_port_vlan_del(rocker_port, untagged_vid, 0);
|
|
if (err)
|
|
if (err)
|
|
return err;
|
|
return err;
|
|
|
|
+
|
|
|
|
+ rocker_port_internal_vlan_id_put(rocker_port,
|
|
|
|
+ rocker_port->bridge_dev->ifindex);
|
|
rocker_port->internal_vlan_id =
|
|
rocker_port->internal_vlan_id =
|
|
rocker_port_internal_vlan_id_get(rocker_port,
|
|
rocker_port_internal_vlan_id_get(rocker_port,
|
|
rocker_port->dev->ifindex);
|
|
rocker_port->dev->ifindex);
|
|
- err = rocker_port_vlan(rocker_port, SWITCHDEV_TRANS_NONE, 0, 0);
|
|
|
|
|
|
+
|
|
|
|
+ rocker_port->bridge_dev = NULL;
|
|
|
|
+
|
|
|
|
+ err = rocker_port_vlan_add(rocker_port, SWITCHDEV_TRANS_NONE,
|
|
|
|
+ untagged_vid, 0);
|
|
if (err)
|
|
if (err)
|
|
return err;
|
|
return err;
|
|
|
|
|