diff options
Diffstat (limited to 'net/bridge/br_mrp.c')
-rw-r--r-- | net/bridge/br_mrp.c | 59 |
1 files changed, 41 insertions, 18 deletions
diff --git a/net/bridge/br_mrp.c b/net/bridge/br_mrp.c index b36689e6e7cb..cec2c4e4561d 100644 --- a/net/bridge/br_mrp.c +++ b/net/bridge/br_mrp.c @@ -6,6 +6,13 @@ static const u8 mrp_test_dmac[ETH_ALEN] = { 0x1, 0x15, 0x4e, 0x0, 0x0, 0x1 }; static const u8 mrp_in_test_dmac[ETH_ALEN] = { 0x1, 0x15, 0x4e, 0x0, 0x0, 0x3 }; +static int br_mrp_process(struct net_bridge_port *p, struct sk_buff *skb); + +static struct br_frame_type mrp_frame_type __read_mostly = { + .type = cpu_to_be16(ETH_P_MRP), + .frame_handler = br_mrp_process, +}; + static bool br_mrp_is_ring_port(struct net_bridge_port *p_port, struct net_bridge_port *s_port, struct net_bridge_port *port) @@ -47,8 +54,8 @@ static struct br_mrp *br_mrp_find_id(struct net_bridge *br, u32 ring_id) struct br_mrp *res = NULL; struct br_mrp *mrp; - list_for_each_entry_rcu(mrp, &br->mrp_list, list, - lockdep_rtnl_is_held()) { + hlist_for_each_entry_rcu(mrp, &br->mrp_list, list, + lockdep_rtnl_is_held()) { if (mrp->ring_id == ring_id) { res = mrp; break; @@ -63,8 +70,8 @@ static struct br_mrp *br_mrp_find_in_id(struct net_bridge *br, u32 in_id) struct br_mrp *res = NULL; struct br_mrp *mrp; - list_for_each_entry_rcu(mrp, &br->mrp_list, list, - lockdep_rtnl_is_held()) { + hlist_for_each_entry_rcu(mrp, &br->mrp_list, list, + lockdep_rtnl_is_held()) { if (mrp->in_id == in_id) { res = mrp; break; @@ -78,8 +85,8 @@ static bool br_mrp_unique_ifindex(struct net_bridge *br, u32 ifindex) { struct br_mrp *mrp; - list_for_each_entry_rcu(mrp, &br->mrp_list, list, - lockdep_rtnl_is_held()) { + hlist_for_each_entry_rcu(mrp, &br->mrp_list, list, + lockdep_rtnl_is_held()) { struct net_bridge_port *p; p = rtnl_dereference(mrp->p_port); @@ -104,8 +111,8 @@ static struct br_mrp *br_mrp_find_port(struct net_bridge *br, struct br_mrp *res = NULL; struct br_mrp *mrp; - list_for_each_entry_rcu(mrp, &br->mrp_list, list, - lockdep_rtnl_is_held()) { + hlist_for_each_entry_rcu(mrp, &br->mrp_list, list, + lockdep_rtnl_is_held()) { if (rcu_access_pointer(mrp->p_port) == p || rcu_access_pointer(mrp->s_port) == p || rcu_access_pointer(mrp->i_port) == p) { @@ -443,8 +450,11 @@ static void br_mrp_del_impl(struct net_bridge *br, struct br_mrp *mrp) rcu_assign_pointer(mrp->i_port, NULL); } - list_del_rcu(&mrp->list); + hlist_del_rcu(&mrp->list); kfree_rcu(mrp, rcu); + + if (hlist_empty(&br->mrp_list)) + br_del_frame(br, &mrp_frame_type); } /* Adds a new MRP instance. @@ -493,9 +503,12 @@ int br_mrp_add(struct net_bridge *br, struct br_mrp_instance *instance) spin_unlock_bh(&br->lock); rcu_assign_pointer(mrp->s_port, p); + if (hlist_empty(&br->mrp_list)) + br_add_frame(br, &mrp_frame_type); + INIT_DELAYED_WORK(&mrp->test_work, br_mrp_test_work_expired); INIT_DELAYED_WORK(&mrp->in_test_work, br_mrp_in_test_work_expired); - list_add_tail_rcu(&mrp->list, &br->mrp_list); + hlist_add_tail_rcu(&mrp->list, &br->mrp_list); err = br_mrp_switchdev_add(br, mrp); if (err) @@ -845,7 +858,8 @@ static bool br_mrp_in_frame(struct sk_buff *skb) if (hdr->type == BR_MRP_TLV_HEADER_IN_TEST || hdr->type == BR_MRP_TLV_HEADER_IN_TOPO || hdr->type == BR_MRP_TLV_HEADER_IN_LINK_DOWN || - hdr->type == BR_MRP_TLV_HEADER_IN_LINK_UP) + hdr->type == BR_MRP_TLV_HEADER_IN_LINK_UP || + hdr->type == BR_MRP_TLV_HEADER_IN_LINK_STATUS) return true; return false; @@ -1113,9 +1127,9 @@ static int br_mrp_rcv(struct net_bridge_port *p, goto no_forward; } } else { - /* MIM should forward IntLinkChange and + /* MIM should forward IntLinkChange/Status and * IntTopoChange between ring ports but MIM - * should not forward IntLinkChange and + * should not forward IntLinkChange/Status and * IntTopoChange if the frame was received at * the interconnect port */ @@ -1142,6 +1156,17 @@ static int br_mrp_rcv(struct net_bridge_port *p, in_type == BR_MRP_TLV_HEADER_IN_LINK_DOWN)) goto forward; + /* MIC should forward IntLinkStatus frames only to + * interconnect port if it was received on a ring port. + * If it is received on interconnect port then, it + * should be forward on both ring ports + */ + if (br_mrp_is_ring_port(p_port, s_port, p) && + in_type == BR_MRP_TLV_HEADER_IN_LINK_STATUS) { + p_dst = NULL; + s_dst = NULL; + } + /* Should forward the InTopo frames only between the * ring ports */ @@ -1172,20 +1197,18 @@ no_forward: * normal forwarding. * note: already called with rcu_read_lock */ -int br_mrp_process(struct net_bridge_port *p, struct sk_buff *skb) +static int br_mrp_process(struct net_bridge_port *p, struct sk_buff *skb) { /* If there is no MRP instance do normal forwarding */ if (likely(!(p->flags & BR_MRP_AWARE))) goto out; - if (unlikely(skb->protocol == htons(ETH_P_MRP))) - return br_mrp_rcv(p, skb, p->dev); - + return br_mrp_rcv(p, skb, p->dev); out: return 0; } bool br_mrp_enabled(struct net_bridge *br) { - return !list_empty(&br->mrp_list); + return !hlist_empty(&br->mrp_list); } |