Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8254973f authored by Simon Horman's avatar Simon Horman Committed by David S. Miller
Browse files

rocker: forward packets to CPU when port is joined to openvswitch



Teach rocker to forward packets to CPU when a port is joined to Open vSwitch.
There is scope to later refine what is passed up as per Open vSwitch flows
on a port.

This does not change the behaviour of rocker ports that are
not joined to Open vSwitch.

Signed-off-by: default avatarSimon Horman <simon.horman@netronome.com>
Acked-by: default avatarScott Feldman <sfeldma@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a7ce45a7
Loading
Loading
Loading
Loading
+50 −12
Original line number Diff line number Diff line
@@ -202,6 +202,7 @@ enum {
	ROCKER_CTRL_IPV4_MCAST,
	ROCKER_CTRL_IPV6_MCAST,
	ROCKER_CTRL_DFLT_BRIDGING,
	ROCKER_CTRL_DFLT_OVS,
	ROCKER_CTRL_MAX,
};

@@ -321,9 +322,21 @@ static u16 rocker_port_vlan_to_vid(const struct rocker_port *rocker_port,
	return ntohs(vlan_id);
}

static bool rocker_port_is_slave(const struct rocker_port *rocker_port,
				   const char *kind)
{
	return rocker_port->bridge_dev &&
		!strcmp(rocker_port->bridge_dev->rtnl_link_ops->kind, kind);
}

static bool rocker_port_is_bridged(const struct rocker_port *rocker_port)
{
	return !!rocker_port->bridge_dev;
	return rocker_port_is_slave(rocker_port, "bridge");
}

static bool rocker_port_is_ovsed(const struct rocker_port *rocker_port)
{
	return rocker_port_is_slave(rocker_port, "openvswitch");
}

#define ROCKER_OP_FLAG_REMOVE		BIT(0)
@@ -3275,6 +3288,12 @@ static struct rocker_ctrl {
		.bridge = true,
		.copy_to_cpu = true,
	},
	[ROCKER_CTRL_DFLT_OVS] = {
		/* pass all pkts up to CPU */
		.eth_dst = zero_mac,
		.eth_dst_mask = zero_mac,
		.acl = true,
	},
};

static int rocker_port_ctrl_vlan_acl(struct rocker_port *rocker_port,
@@ -3787,11 +3806,14 @@ static int rocker_port_stp_update(struct rocker_port *rocker_port,
		break;
	case BR_STATE_LEARNING:
	case BR_STATE_FORWARDING:
		if (!rocker_port_is_ovsed(rocker_port))
			want[ROCKER_CTRL_LINK_LOCAL_MCAST] = true;
		want[ROCKER_CTRL_IPV4_MCAST] = true;
		want[ROCKER_CTRL_IPV6_MCAST] = true;
		if (rocker_port_is_bridged(rocker_port))
			want[ROCKER_CTRL_DFLT_BRIDGING] = true;
		else if (rocker_port_is_ovsed(rocker_port))
			want[ROCKER_CTRL_DFLT_OVS] = true;
		else
			want[ROCKER_CTRL_LOCAL_ARP] = true;
		break;
@@ -5264,23 +5286,39 @@ static int rocker_port_bridge_leave(struct rocker_port *rocker_port)
	return err;
}


static int rocker_port_ovs_changed(struct rocker_port *rocker_port,
				   struct net_device *master)
{
	int err;

	rocker_port->bridge_dev = master;

	err = rocker_port_fwd_disable(rocker_port, SWITCHDEV_TRANS_NONE, 0);
	if (err)
		return err;
	err = rocker_port_fwd_enable(rocker_port, SWITCHDEV_TRANS_NONE, 0);

	return err;
}

static int rocker_port_master_changed(struct net_device *dev)
{
	struct rocker_port *rocker_port = netdev_priv(dev);
	struct net_device *master = netdev_master_upper_dev_get(dev);
	int err = 0;

	/* There are currently three cases handled here:
	 * 1. Joining a bridge
	 * 2. Leaving a previously joined bridge
	 * 3. Other, e.g. being added to or removed from a bond or openvswitch,
	 *    in which case nothing is done
	 */
	if (master && master->rtnl_link_ops &&
	    !strcmp(master->rtnl_link_ops->kind, "bridge"))
	/* N.B: Do nothing if the type of master is not supported */
	if (master && master->rtnl_link_ops) {
		if (!strcmp(master->rtnl_link_ops->kind, "bridge"))
			err = rocker_port_bridge_join(rocker_port, master);
	else if (rocker_port_is_bridged(rocker_port))
		else if (!strcmp(master->rtnl_link_ops->kind, "openvswitch"))
			err = rocker_port_ovs_changed(rocker_port, master);
	} else if (rocker_port_is_bridged(rocker_port)) {
		err = rocker_port_bridge_leave(rocker_port);
	} else if (rocker_port_is_ovsed(rocker_port)) {
		err = rocker_port_ovs_changed(rocker_port, NULL);
	}

	return err;
}