| Index: net/openvswitch/vport-internal_dev.c |
| =================================================================== |
| --- a/net/openvswitch/vport-internal_dev.c |
| +++ b/net/openvswitch/vport-internal_dev.c |
| @@ -113,12 +113,58 @@ internal_get_stats(struct net_device *de |
| } |
| } |
| |
| +static int internal_dev_fill_forward_path(struct net_device_path_ctx *ctx, struct net_device_path *path) |
| +{ |
| + struct vport *vport; |
| + int i; |
| + struct table_instance *ti; |
| + struct datapath *dp; |
| + struct sw_flow_key *key; |
| + struct sw_flow_actions *sf_acts; |
| + struct nlattr *a; |
| + int rem; |
| + |
| + vport = ovs_internal_dev_get_vport(ctx->dev); |
| + dp = vport->dp; |
| + ti = rcu_dereference_ovsl(dp->table.ti); |
| + |
| + for (i = 0; i < ti->n_buckets; i++) { |
| + struct sw_flow *flow; |
| + struct hlist_head *head = &ti->buckets[i]; |
| + struct hlist_node *n; |
| + |
| + hlist_for_each_entry_safe(flow, n, head, flow_table.node[ti->node_ver]) { |
| + key = &flow->key; |
| + |
| + if((!memcmp(ctx->dev->dev_addr, key->eth.dst, ETH_ALEN)) && (!memcmp(ctx->daddr, key->eth.src, ETH_ALEN))){ |
| + sf_acts = rcu_dereference_ovsl(flow->sf_acts); |
| + for (a = sf_acts->actions, rem = sf_acts->actions_len; rem > 0; |
| + a = nla_next(a, &rem)) { |
| + if(nla_type(a) == OVS_ACTION_ATTR_OUTPUT){ |
| + vport = ovs_vport_rcu(dp, key->phy.in_port); |
| + goto out; |
| + } |
| + } |
| + } |
| + } |
| + } |
| + |
| +out: |
| + |
| + path->type = DEV_PATH_BRIDGE; |
| + path->dev = ctx->dev; |
| + ctx->dev = vport->dev; |
| + |
| + return 0; |
| +} |
| + |
| static const struct net_device_ops internal_dev_netdev_ops = { |
| .ndo_open = internal_dev_open, |
| .ndo_stop = internal_dev_stop, |
| .ndo_start_xmit = internal_dev_xmit, |
| .ndo_set_mac_address = eth_mac_addr, |
| .ndo_get_stats64 = internal_get_stats, |
| + .ndo_fill_forward_path = internal_dev_fill_forward_path, |
| }; |
| |
| static struct rtnl_link_ops internal_dev_link_ops __read_mostly = { |