19a9f26e8SHoratiu Vultur // SPDX-License-Identifier: GPL-2.0-or-later 29a9f26e8SHoratiu Vultur 39a9f26e8SHoratiu Vultur #include <linux/mrp_bridge.h> 49a9f26e8SHoratiu Vultur #include "br_private_mrp.h" 59a9f26e8SHoratiu Vultur 69a9f26e8SHoratiu Vultur static const u8 mrp_test_dmac[ETH_ALEN] = { 0x1, 0x15, 0x4e, 0x0, 0x0, 0x1 }; 7537ed567SHoratiu Vultur static const u8 mrp_in_test_dmac[ETH_ALEN] = { 0x1, 0x15, 0x4e, 0x0, 0x0, 0x3 }; 8537ed567SHoratiu Vultur 990c628ddSHenrik Bjoernlund static int br_mrp_process(struct net_bridge_port *p, struct sk_buff *skb); 1090c628ddSHenrik Bjoernlund 1190c628ddSHenrik Bjoernlund static struct br_frame_type mrp_frame_type __read_mostly = { 1290c628ddSHenrik Bjoernlund .type = cpu_to_be16(ETH_P_MRP), 1390c628ddSHenrik Bjoernlund .frame_handler = br_mrp_process, 1490c628ddSHenrik Bjoernlund }; 1590c628ddSHenrik Bjoernlund 16537ed567SHoratiu Vultur static bool br_mrp_is_ring_port(struct net_bridge_port *p_port, 17537ed567SHoratiu Vultur struct net_bridge_port *s_port, 18537ed567SHoratiu Vultur struct net_bridge_port *port) 19537ed567SHoratiu Vultur { 20537ed567SHoratiu Vultur if (port == p_port || 21537ed567SHoratiu Vultur port == s_port) 22537ed567SHoratiu Vultur return true; 23537ed567SHoratiu Vultur 24537ed567SHoratiu Vultur return false; 25537ed567SHoratiu Vultur } 26537ed567SHoratiu Vultur 27537ed567SHoratiu Vultur static bool br_mrp_is_in_port(struct net_bridge_port *i_port, 28537ed567SHoratiu Vultur struct net_bridge_port *port) 29537ed567SHoratiu Vultur { 30537ed567SHoratiu Vultur if (port == i_port) 31537ed567SHoratiu Vultur return true; 32537ed567SHoratiu Vultur 33537ed567SHoratiu Vultur return false; 34537ed567SHoratiu Vultur } 359a9f26e8SHoratiu Vultur 369a9f26e8SHoratiu Vultur static struct net_bridge_port *br_mrp_get_port(struct net_bridge *br, 379a9f26e8SHoratiu Vultur u32 ifindex) 389a9f26e8SHoratiu Vultur { 399a9f26e8SHoratiu Vultur struct net_bridge_port *res = NULL; 409a9f26e8SHoratiu Vultur struct net_bridge_port *port; 419a9f26e8SHoratiu Vultur 429a9f26e8SHoratiu Vultur list_for_each_entry(port, &br->port_list, list) { 439a9f26e8SHoratiu Vultur if (port->dev->ifindex == ifindex) { 449a9f26e8SHoratiu Vultur res = port; 459a9f26e8SHoratiu Vultur break; 469a9f26e8SHoratiu Vultur } 479a9f26e8SHoratiu Vultur } 489a9f26e8SHoratiu Vultur 499a9f26e8SHoratiu Vultur return res; 509a9f26e8SHoratiu Vultur } 519a9f26e8SHoratiu Vultur 529a9f26e8SHoratiu Vultur static struct br_mrp *br_mrp_find_id(struct net_bridge *br, u32 ring_id) 539a9f26e8SHoratiu Vultur { 549a9f26e8SHoratiu Vultur struct br_mrp *res = NULL; 559a9f26e8SHoratiu Vultur struct br_mrp *mrp; 569a9f26e8SHoratiu Vultur 570169b820SHoratiu Vultur hlist_for_each_entry_rcu(mrp, &br->mrp_list, list, 589a9f26e8SHoratiu Vultur lockdep_rtnl_is_held()) { 599a9f26e8SHoratiu Vultur if (mrp->ring_id == ring_id) { 609a9f26e8SHoratiu Vultur res = mrp; 619a9f26e8SHoratiu Vultur break; 629a9f26e8SHoratiu Vultur } 639a9f26e8SHoratiu Vultur } 649a9f26e8SHoratiu Vultur 659a9f26e8SHoratiu Vultur return res; 669a9f26e8SHoratiu Vultur } 679a9f26e8SHoratiu Vultur 68537ed567SHoratiu Vultur static struct br_mrp *br_mrp_find_in_id(struct net_bridge *br, u32 in_id) 69537ed567SHoratiu Vultur { 70537ed567SHoratiu Vultur struct br_mrp *res = NULL; 71537ed567SHoratiu Vultur struct br_mrp *mrp; 72537ed567SHoratiu Vultur 730169b820SHoratiu Vultur hlist_for_each_entry_rcu(mrp, &br->mrp_list, list, 74537ed567SHoratiu Vultur lockdep_rtnl_is_held()) { 75537ed567SHoratiu Vultur if (mrp->in_id == in_id) { 76537ed567SHoratiu Vultur res = mrp; 77537ed567SHoratiu Vultur break; 78537ed567SHoratiu Vultur } 79537ed567SHoratiu Vultur } 80537ed567SHoratiu Vultur 81537ed567SHoratiu Vultur return res; 82537ed567SHoratiu Vultur } 83537ed567SHoratiu Vultur 847aa38018SHoratiu Vultur static bool br_mrp_unique_ifindex(struct net_bridge *br, u32 ifindex) 857aa38018SHoratiu Vultur { 867aa38018SHoratiu Vultur struct br_mrp *mrp; 877aa38018SHoratiu Vultur 880169b820SHoratiu Vultur hlist_for_each_entry_rcu(mrp, &br->mrp_list, list, 897aa38018SHoratiu Vultur lockdep_rtnl_is_held()) { 907aa38018SHoratiu Vultur struct net_bridge_port *p; 917aa38018SHoratiu Vultur 927aa38018SHoratiu Vultur p = rtnl_dereference(mrp->p_port); 937aa38018SHoratiu Vultur if (p && p->dev->ifindex == ifindex) 947aa38018SHoratiu Vultur return false; 957aa38018SHoratiu Vultur 967aa38018SHoratiu Vultur p = rtnl_dereference(mrp->s_port); 977aa38018SHoratiu Vultur if (p && p->dev->ifindex == ifindex) 987aa38018SHoratiu Vultur return false; 99537ed567SHoratiu Vultur 100537ed567SHoratiu Vultur p = rtnl_dereference(mrp->i_port); 101537ed567SHoratiu Vultur if (p && p->dev->ifindex == ifindex) 102537ed567SHoratiu Vultur return false; 1037aa38018SHoratiu Vultur } 1047aa38018SHoratiu Vultur 1057aa38018SHoratiu Vultur return true; 1067aa38018SHoratiu Vultur } 1077aa38018SHoratiu Vultur 1089a9f26e8SHoratiu Vultur static struct br_mrp *br_mrp_find_port(struct net_bridge *br, 1099a9f26e8SHoratiu Vultur struct net_bridge_port *p) 1109a9f26e8SHoratiu Vultur { 1119a9f26e8SHoratiu Vultur struct br_mrp *res = NULL; 1129a9f26e8SHoratiu Vultur struct br_mrp *mrp; 1139a9f26e8SHoratiu Vultur 1140169b820SHoratiu Vultur hlist_for_each_entry_rcu(mrp, &br->mrp_list, list, 1159a9f26e8SHoratiu Vultur lockdep_rtnl_is_held()) { 1169a9f26e8SHoratiu Vultur if (rcu_access_pointer(mrp->p_port) == p || 117537ed567SHoratiu Vultur rcu_access_pointer(mrp->s_port) == p || 118537ed567SHoratiu Vultur rcu_access_pointer(mrp->i_port) == p) { 1199a9f26e8SHoratiu Vultur res = mrp; 1209a9f26e8SHoratiu Vultur break; 1219a9f26e8SHoratiu Vultur } 1229a9f26e8SHoratiu Vultur } 1239a9f26e8SHoratiu Vultur 1249a9f26e8SHoratiu Vultur return res; 1259a9f26e8SHoratiu Vultur } 1269a9f26e8SHoratiu Vultur 1279a9f26e8SHoratiu Vultur static int br_mrp_next_seq(struct br_mrp *mrp) 1289a9f26e8SHoratiu Vultur { 1299a9f26e8SHoratiu Vultur mrp->seq_id++; 1309a9f26e8SHoratiu Vultur return mrp->seq_id; 1319a9f26e8SHoratiu Vultur } 1329a9f26e8SHoratiu Vultur 1339a9f26e8SHoratiu Vultur static struct sk_buff *br_mrp_skb_alloc(struct net_bridge_port *p, 1349a9f26e8SHoratiu Vultur const u8 *src, const u8 *dst) 1359a9f26e8SHoratiu Vultur { 1369a9f26e8SHoratiu Vultur struct ethhdr *eth_hdr; 1379a9f26e8SHoratiu Vultur struct sk_buff *skb; 1389b14d1f8SHoratiu Vultur __be16 *version; 1399a9f26e8SHoratiu Vultur 1409a9f26e8SHoratiu Vultur skb = dev_alloc_skb(MRP_MAX_FRAME_LENGTH); 1419a9f26e8SHoratiu Vultur if (!skb) 1429a9f26e8SHoratiu Vultur return NULL; 1439a9f26e8SHoratiu Vultur 1449a9f26e8SHoratiu Vultur skb->dev = p->dev; 1459a9f26e8SHoratiu Vultur skb->protocol = htons(ETH_P_MRP); 1469a9f26e8SHoratiu Vultur skb->priority = MRP_FRAME_PRIO; 1479a9f26e8SHoratiu Vultur skb_reserve(skb, sizeof(*eth_hdr)); 1489a9f26e8SHoratiu Vultur 1499a9f26e8SHoratiu Vultur eth_hdr = skb_push(skb, sizeof(*eth_hdr)); 1509a9f26e8SHoratiu Vultur ether_addr_copy(eth_hdr->h_dest, dst); 1519a9f26e8SHoratiu Vultur ether_addr_copy(eth_hdr->h_source, src); 1529a9f26e8SHoratiu Vultur eth_hdr->h_proto = htons(ETH_P_MRP); 1539a9f26e8SHoratiu Vultur 1549a9f26e8SHoratiu Vultur version = skb_put(skb, sizeof(*version)); 1559a9f26e8SHoratiu Vultur *version = cpu_to_be16(MRP_VERSION); 1569a9f26e8SHoratiu Vultur 1579a9f26e8SHoratiu Vultur return skb; 1589a9f26e8SHoratiu Vultur } 1599a9f26e8SHoratiu Vultur 1609a9f26e8SHoratiu Vultur static void br_mrp_skb_tlv(struct sk_buff *skb, 1619a9f26e8SHoratiu Vultur enum br_mrp_tlv_header_type type, 1629a9f26e8SHoratiu Vultur u8 length) 1639a9f26e8SHoratiu Vultur { 1649a9f26e8SHoratiu Vultur struct br_mrp_tlv_hdr *hdr; 1659a9f26e8SHoratiu Vultur 1669a9f26e8SHoratiu Vultur hdr = skb_put(skb, sizeof(*hdr)); 1679a9f26e8SHoratiu Vultur hdr->type = type; 1689a9f26e8SHoratiu Vultur hdr->length = length; 1699a9f26e8SHoratiu Vultur } 1709a9f26e8SHoratiu Vultur 1719a9f26e8SHoratiu Vultur static void br_mrp_skb_common(struct sk_buff *skb, struct br_mrp *mrp) 1729a9f26e8SHoratiu Vultur { 1739a9f26e8SHoratiu Vultur struct br_mrp_common_hdr *hdr; 1749a9f26e8SHoratiu Vultur 1759a9f26e8SHoratiu Vultur br_mrp_skb_tlv(skb, BR_MRP_TLV_HEADER_COMMON, sizeof(*hdr)); 1769a9f26e8SHoratiu Vultur 1779a9f26e8SHoratiu Vultur hdr = skb_put(skb, sizeof(*hdr)); 1789a9f26e8SHoratiu Vultur hdr->seq_id = cpu_to_be16(br_mrp_next_seq(mrp)); 1799a9f26e8SHoratiu Vultur memset(hdr->domain, 0xff, MRP_DOMAIN_UUID_LENGTH); 1809a9f26e8SHoratiu Vultur } 1819a9f26e8SHoratiu Vultur 1829a9f26e8SHoratiu Vultur static struct sk_buff *br_mrp_alloc_test_skb(struct br_mrp *mrp, 1839a9f26e8SHoratiu Vultur struct net_bridge_port *p, 1849a9f26e8SHoratiu Vultur enum br_mrp_port_role_type port_role) 1859a9f26e8SHoratiu Vultur { 1869a9f26e8SHoratiu Vultur struct br_mrp_ring_test_hdr *hdr = NULL; 1879a9f26e8SHoratiu Vultur struct sk_buff *skb = NULL; 1889a9f26e8SHoratiu Vultur 1899a9f26e8SHoratiu Vultur if (!p) 1909a9f26e8SHoratiu Vultur return NULL; 1919a9f26e8SHoratiu Vultur 1929a9f26e8SHoratiu Vultur skb = br_mrp_skb_alloc(p, p->dev->dev_addr, mrp_test_dmac); 1939a9f26e8SHoratiu Vultur if (!skb) 1949a9f26e8SHoratiu Vultur return NULL; 1959a9f26e8SHoratiu Vultur 1969a9f26e8SHoratiu Vultur br_mrp_skb_tlv(skb, BR_MRP_TLV_HEADER_RING_TEST, sizeof(*hdr)); 1979a9f26e8SHoratiu Vultur hdr = skb_put(skb, sizeof(*hdr)); 1989a9f26e8SHoratiu Vultur 1994b3a61b0SHoratiu Vultur hdr->prio = cpu_to_be16(mrp->prio); 2009a9f26e8SHoratiu Vultur ether_addr_copy(hdr->sa, p->br->dev->dev_addr); 2019a9f26e8SHoratiu Vultur hdr->port_role = cpu_to_be16(port_role); 2029a9f26e8SHoratiu Vultur hdr->state = cpu_to_be16(mrp->ring_state); 2039a9f26e8SHoratiu Vultur hdr->transitions = cpu_to_be16(mrp->ring_transitions); 2049a9f26e8SHoratiu Vultur hdr->timestamp = cpu_to_be32(jiffies_to_msecs(jiffies)); 2059a9f26e8SHoratiu Vultur 2069a9f26e8SHoratiu Vultur br_mrp_skb_common(skb, mrp); 2079a9f26e8SHoratiu Vultur br_mrp_skb_tlv(skb, BR_MRP_TLV_HEADER_END, 0x0); 2089a9f26e8SHoratiu Vultur 2099a9f26e8SHoratiu Vultur return skb; 2109a9f26e8SHoratiu Vultur } 2119a9f26e8SHoratiu Vultur 212537ed567SHoratiu Vultur static struct sk_buff *br_mrp_alloc_in_test_skb(struct br_mrp *mrp, 213537ed567SHoratiu Vultur struct net_bridge_port *p, 214537ed567SHoratiu Vultur enum br_mrp_port_role_type port_role) 215537ed567SHoratiu Vultur { 216537ed567SHoratiu Vultur struct br_mrp_in_test_hdr *hdr = NULL; 217537ed567SHoratiu Vultur struct sk_buff *skb = NULL; 218537ed567SHoratiu Vultur 219537ed567SHoratiu Vultur if (!p) 220537ed567SHoratiu Vultur return NULL; 221537ed567SHoratiu Vultur 222537ed567SHoratiu Vultur skb = br_mrp_skb_alloc(p, p->dev->dev_addr, mrp_in_test_dmac); 223537ed567SHoratiu Vultur if (!skb) 224537ed567SHoratiu Vultur return NULL; 225537ed567SHoratiu Vultur 226537ed567SHoratiu Vultur br_mrp_skb_tlv(skb, BR_MRP_TLV_HEADER_IN_TEST, sizeof(*hdr)); 227537ed567SHoratiu Vultur hdr = skb_put(skb, sizeof(*hdr)); 228537ed567SHoratiu Vultur 229537ed567SHoratiu Vultur hdr->id = cpu_to_be16(mrp->in_id); 230537ed567SHoratiu Vultur ether_addr_copy(hdr->sa, p->br->dev->dev_addr); 231537ed567SHoratiu Vultur hdr->port_role = cpu_to_be16(port_role); 232537ed567SHoratiu Vultur hdr->state = cpu_to_be16(mrp->in_state); 233537ed567SHoratiu Vultur hdr->transitions = cpu_to_be16(mrp->in_transitions); 234537ed567SHoratiu Vultur hdr->timestamp = cpu_to_be32(jiffies_to_msecs(jiffies)); 235537ed567SHoratiu Vultur 236537ed567SHoratiu Vultur br_mrp_skb_common(skb, mrp); 237537ed567SHoratiu Vultur br_mrp_skb_tlv(skb, BR_MRP_TLV_HEADER_END, 0x0); 238537ed567SHoratiu Vultur 239537ed567SHoratiu Vultur return skb; 240537ed567SHoratiu Vultur } 241537ed567SHoratiu Vultur 242c6676e7dSHoratiu Vultur /* This function is continuously called in the following cases: 243c6676e7dSHoratiu Vultur * - when node role is MRM, in this case test_monitor is always set to false 244c6676e7dSHoratiu Vultur * because it needs to notify the userspace that the ring is open and needs to 245c6676e7dSHoratiu Vultur * send MRP_Test frames 246c6676e7dSHoratiu Vultur * - when node role is MRA, there are 2 subcases: 247c6676e7dSHoratiu Vultur * - when MRA behaves as MRM, in this case is similar with MRM role 248c6676e7dSHoratiu Vultur * - when MRA behaves as MRC, in this case test_monitor is set to true, 249c6676e7dSHoratiu Vultur * because it needs to detect when it stops seeing MRP_Test frames 250c6676e7dSHoratiu Vultur * from MRM node but it doesn't need to send MRP_Test frames. 251c6676e7dSHoratiu Vultur */ 2529a9f26e8SHoratiu Vultur static void br_mrp_test_work_expired(struct work_struct *work) 2539a9f26e8SHoratiu Vultur { 2549a9f26e8SHoratiu Vultur struct delayed_work *del_work = to_delayed_work(work); 2559a9f26e8SHoratiu Vultur struct br_mrp *mrp = container_of(del_work, struct br_mrp, test_work); 2569a9f26e8SHoratiu Vultur struct net_bridge_port *p; 2579a9f26e8SHoratiu Vultur bool notify_open = false; 2589a9f26e8SHoratiu Vultur struct sk_buff *skb; 2599a9f26e8SHoratiu Vultur 2609a9f26e8SHoratiu Vultur if (time_before_eq(mrp->test_end, jiffies)) 2619a9f26e8SHoratiu Vultur return; 2629a9f26e8SHoratiu Vultur 2639a9f26e8SHoratiu Vultur if (mrp->test_count_miss < mrp->test_max_miss) { 2649a9f26e8SHoratiu Vultur mrp->test_count_miss++; 2659a9f26e8SHoratiu Vultur } else { 2669a9f26e8SHoratiu Vultur /* Notify that the ring is open only if the ring state is 2679a9f26e8SHoratiu Vultur * closed, otherwise it would continue to notify at every 2689a9f26e8SHoratiu Vultur * interval. 269c6676e7dSHoratiu Vultur * Also notify that the ring is open when the node has the 270c6676e7dSHoratiu Vultur * role MRA and behaves as MRC. The reason is that the 271c6676e7dSHoratiu Vultur * userspace needs to know when the MRM stopped sending 272c6676e7dSHoratiu Vultur * MRP_Test frames so that the current node to try to take 273c6676e7dSHoratiu Vultur * the role of a MRM. 2749a9f26e8SHoratiu Vultur */ 275c6676e7dSHoratiu Vultur if (mrp->ring_state == BR_MRP_RING_STATE_CLOSED || 276c6676e7dSHoratiu Vultur mrp->test_monitor) 2779a9f26e8SHoratiu Vultur notify_open = true; 2789a9f26e8SHoratiu Vultur } 2799a9f26e8SHoratiu Vultur 2809a9f26e8SHoratiu Vultur rcu_read_lock(); 2819a9f26e8SHoratiu Vultur 2829a9f26e8SHoratiu Vultur p = rcu_dereference(mrp->p_port); 2839a9f26e8SHoratiu Vultur if (p) { 284c6676e7dSHoratiu Vultur if (!mrp->test_monitor) { 285c6676e7dSHoratiu Vultur skb = br_mrp_alloc_test_skb(mrp, p, 286c6676e7dSHoratiu Vultur BR_MRP_PORT_ROLE_PRIMARY); 2879a9f26e8SHoratiu Vultur if (!skb) 2889a9f26e8SHoratiu Vultur goto out; 2899a9f26e8SHoratiu Vultur 2909a9f26e8SHoratiu Vultur skb_reset_network_header(skb); 2919a9f26e8SHoratiu Vultur dev_queue_xmit(skb); 292c6676e7dSHoratiu Vultur } 2939a9f26e8SHoratiu Vultur 2949a9f26e8SHoratiu Vultur if (notify_open && !mrp->ring_role_offloaded) 2954cc625c6SHoratiu Vultur br_mrp_ring_port_open(p->dev, true); 2969a9f26e8SHoratiu Vultur } 2979a9f26e8SHoratiu Vultur 2989a9f26e8SHoratiu Vultur p = rcu_dereference(mrp->s_port); 2999a9f26e8SHoratiu Vultur if (p) { 300c6676e7dSHoratiu Vultur if (!mrp->test_monitor) { 301c6676e7dSHoratiu Vultur skb = br_mrp_alloc_test_skb(mrp, p, 302c6676e7dSHoratiu Vultur BR_MRP_PORT_ROLE_SECONDARY); 3039a9f26e8SHoratiu Vultur if (!skb) 3049a9f26e8SHoratiu Vultur goto out; 3059a9f26e8SHoratiu Vultur 3069a9f26e8SHoratiu Vultur skb_reset_network_header(skb); 3079a9f26e8SHoratiu Vultur dev_queue_xmit(skb); 308c6676e7dSHoratiu Vultur } 3099a9f26e8SHoratiu Vultur 3109a9f26e8SHoratiu Vultur if (notify_open && !mrp->ring_role_offloaded) 3114cc625c6SHoratiu Vultur br_mrp_ring_port_open(p->dev, true); 3129a9f26e8SHoratiu Vultur } 3139a9f26e8SHoratiu Vultur 3149a9f26e8SHoratiu Vultur out: 3159a9f26e8SHoratiu Vultur rcu_read_unlock(); 3169a9f26e8SHoratiu Vultur 3179a9f26e8SHoratiu Vultur queue_delayed_work(system_wq, &mrp->test_work, 3189a9f26e8SHoratiu Vultur usecs_to_jiffies(mrp->test_interval)); 3199a9f26e8SHoratiu Vultur } 3209a9f26e8SHoratiu Vultur 321537ed567SHoratiu Vultur /* This function is continuously called when the node has the interconnect role 322537ed567SHoratiu Vultur * MIM. It would generate interconnect test frames and will send them on all 3 323537ed567SHoratiu Vultur * ports. But will also check if it stop receiving interconnect test frames. 324537ed567SHoratiu Vultur */ 325537ed567SHoratiu Vultur static void br_mrp_in_test_work_expired(struct work_struct *work) 326537ed567SHoratiu Vultur { 327537ed567SHoratiu Vultur struct delayed_work *del_work = to_delayed_work(work); 328537ed567SHoratiu Vultur struct br_mrp *mrp = container_of(del_work, struct br_mrp, in_test_work); 329537ed567SHoratiu Vultur struct net_bridge_port *p; 330537ed567SHoratiu Vultur bool notify_open = false; 331537ed567SHoratiu Vultur struct sk_buff *skb; 332537ed567SHoratiu Vultur 333537ed567SHoratiu Vultur if (time_before_eq(mrp->in_test_end, jiffies)) 334537ed567SHoratiu Vultur return; 335537ed567SHoratiu Vultur 336537ed567SHoratiu Vultur if (mrp->in_test_count_miss < mrp->in_test_max_miss) { 337537ed567SHoratiu Vultur mrp->in_test_count_miss++; 338537ed567SHoratiu Vultur } else { 339537ed567SHoratiu Vultur /* Notify that the interconnect ring is open only if the 340537ed567SHoratiu Vultur * interconnect ring state is closed, otherwise it would 341537ed567SHoratiu Vultur * continue to notify at every interval. 342537ed567SHoratiu Vultur */ 343537ed567SHoratiu Vultur if (mrp->in_state == BR_MRP_IN_STATE_CLOSED) 344537ed567SHoratiu Vultur notify_open = true; 345537ed567SHoratiu Vultur } 346537ed567SHoratiu Vultur 347537ed567SHoratiu Vultur rcu_read_lock(); 348537ed567SHoratiu Vultur 349537ed567SHoratiu Vultur p = rcu_dereference(mrp->p_port); 350537ed567SHoratiu Vultur if (p) { 351537ed567SHoratiu Vultur skb = br_mrp_alloc_in_test_skb(mrp, p, 352537ed567SHoratiu Vultur BR_MRP_PORT_ROLE_PRIMARY); 353537ed567SHoratiu Vultur if (!skb) 354537ed567SHoratiu Vultur goto out; 355537ed567SHoratiu Vultur 356537ed567SHoratiu Vultur skb_reset_network_header(skb); 357537ed567SHoratiu Vultur dev_queue_xmit(skb); 358537ed567SHoratiu Vultur 359537ed567SHoratiu Vultur if (notify_open && !mrp->in_role_offloaded) 360537ed567SHoratiu Vultur br_mrp_in_port_open(p->dev, true); 361537ed567SHoratiu Vultur } 362537ed567SHoratiu Vultur 363537ed567SHoratiu Vultur p = rcu_dereference(mrp->s_port); 364537ed567SHoratiu Vultur if (p) { 365537ed567SHoratiu Vultur skb = br_mrp_alloc_in_test_skb(mrp, p, 366537ed567SHoratiu Vultur BR_MRP_PORT_ROLE_SECONDARY); 367537ed567SHoratiu Vultur if (!skb) 368537ed567SHoratiu Vultur goto out; 369537ed567SHoratiu Vultur 370537ed567SHoratiu Vultur skb_reset_network_header(skb); 371537ed567SHoratiu Vultur dev_queue_xmit(skb); 372537ed567SHoratiu Vultur 373537ed567SHoratiu Vultur if (notify_open && !mrp->in_role_offloaded) 374537ed567SHoratiu Vultur br_mrp_in_port_open(p->dev, true); 375537ed567SHoratiu Vultur } 376537ed567SHoratiu Vultur 377537ed567SHoratiu Vultur p = rcu_dereference(mrp->i_port); 378537ed567SHoratiu Vultur if (p) { 379537ed567SHoratiu Vultur skb = br_mrp_alloc_in_test_skb(mrp, p, 380537ed567SHoratiu Vultur BR_MRP_PORT_ROLE_INTER); 381537ed567SHoratiu Vultur if (!skb) 382537ed567SHoratiu Vultur goto out; 383537ed567SHoratiu Vultur 384537ed567SHoratiu Vultur skb_reset_network_header(skb); 385537ed567SHoratiu Vultur dev_queue_xmit(skb); 386537ed567SHoratiu Vultur 387537ed567SHoratiu Vultur if (notify_open && !mrp->in_role_offloaded) 388537ed567SHoratiu Vultur br_mrp_in_port_open(p->dev, true); 389537ed567SHoratiu Vultur } 390537ed567SHoratiu Vultur 391537ed567SHoratiu Vultur out: 392537ed567SHoratiu Vultur rcu_read_unlock(); 393537ed567SHoratiu Vultur 394537ed567SHoratiu Vultur queue_delayed_work(system_wq, &mrp->in_test_work, 395537ed567SHoratiu Vultur usecs_to_jiffies(mrp->in_test_interval)); 396537ed567SHoratiu Vultur } 397537ed567SHoratiu Vultur 3989a9f26e8SHoratiu Vultur /* Deletes the MRP instance. 3999a9f26e8SHoratiu Vultur * note: called under rtnl_lock 4009a9f26e8SHoratiu Vultur */ 4019a9f26e8SHoratiu Vultur static void br_mrp_del_impl(struct net_bridge *br, struct br_mrp *mrp) 4029a9f26e8SHoratiu Vultur { 4039a9f26e8SHoratiu Vultur struct net_bridge_port *p; 4044fb13499SHoratiu Vultur u8 state; 4059a9f26e8SHoratiu Vultur 4069a9f26e8SHoratiu Vultur /* Stop sending MRP_Test frames */ 4079a9f26e8SHoratiu Vultur cancel_delayed_work_sync(&mrp->test_work); 408c6676e7dSHoratiu Vultur br_mrp_switchdev_send_ring_test(br, mrp, 0, 0, 0, 0); 4099a9f26e8SHoratiu Vultur 410537ed567SHoratiu Vultur /* Stop sending MRP_InTest frames if has an interconnect role */ 411537ed567SHoratiu Vultur cancel_delayed_work_sync(&mrp->in_test_work); 412537ed567SHoratiu Vultur br_mrp_switchdev_send_in_test(br, mrp, 0, 0, 0); 413537ed567SHoratiu Vultur 4149a9f26e8SHoratiu Vultur br_mrp_switchdev_del(br, mrp); 4159a9f26e8SHoratiu Vultur 4169a9f26e8SHoratiu Vultur /* Reset the ports */ 4179a9f26e8SHoratiu Vultur p = rtnl_dereference(mrp->p_port); 4189a9f26e8SHoratiu Vultur if (p) { 4199a9f26e8SHoratiu Vultur spin_lock_bh(&br->lock); 4204fb13499SHoratiu Vultur state = netif_running(br->dev) ? 4214fb13499SHoratiu Vultur BR_STATE_FORWARDING : BR_STATE_DISABLED; 4224fb13499SHoratiu Vultur p->state = state; 4239a9f26e8SHoratiu Vultur p->flags &= ~BR_MRP_AWARE; 4249a9f26e8SHoratiu Vultur spin_unlock_bh(&br->lock); 4254fb13499SHoratiu Vultur br_mrp_port_switchdev_set_state(p, state); 4269a9f26e8SHoratiu Vultur rcu_assign_pointer(mrp->p_port, NULL); 4279a9f26e8SHoratiu Vultur } 4289a9f26e8SHoratiu Vultur 4299a9f26e8SHoratiu Vultur p = rtnl_dereference(mrp->s_port); 4309a9f26e8SHoratiu Vultur if (p) { 4319a9f26e8SHoratiu Vultur spin_lock_bh(&br->lock); 4324fb13499SHoratiu Vultur state = netif_running(br->dev) ? 4334fb13499SHoratiu Vultur BR_STATE_FORWARDING : BR_STATE_DISABLED; 4344fb13499SHoratiu Vultur p->state = state; 4359a9f26e8SHoratiu Vultur p->flags &= ~BR_MRP_AWARE; 4369a9f26e8SHoratiu Vultur spin_unlock_bh(&br->lock); 4374fb13499SHoratiu Vultur br_mrp_port_switchdev_set_state(p, state); 4389a9f26e8SHoratiu Vultur rcu_assign_pointer(mrp->s_port, NULL); 4399a9f26e8SHoratiu Vultur } 4409a9f26e8SHoratiu Vultur 441537ed567SHoratiu Vultur p = rtnl_dereference(mrp->i_port); 442537ed567SHoratiu Vultur if (p) { 443537ed567SHoratiu Vultur spin_lock_bh(&br->lock); 444537ed567SHoratiu Vultur state = netif_running(br->dev) ? 445537ed567SHoratiu Vultur BR_STATE_FORWARDING : BR_STATE_DISABLED; 446537ed567SHoratiu Vultur p->state = state; 447537ed567SHoratiu Vultur p->flags &= ~BR_MRP_AWARE; 448537ed567SHoratiu Vultur spin_unlock_bh(&br->lock); 449537ed567SHoratiu Vultur br_mrp_port_switchdev_set_state(p, state); 450537ed567SHoratiu Vultur rcu_assign_pointer(mrp->i_port, NULL); 451537ed567SHoratiu Vultur } 452537ed567SHoratiu Vultur 4530169b820SHoratiu Vultur hlist_del_rcu(&mrp->list); 4549a9f26e8SHoratiu Vultur kfree_rcu(mrp, rcu); 45590c628ddSHenrik Bjoernlund 4560169b820SHoratiu Vultur if (hlist_empty(&br->mrp_list)) 45790c628ddSHenrik Bjoernlund br_del_frame(br, &mrp_frame_type); 4589a9f26e8SHoratiu Vultur } 4599a9f26e8SHoratiu Vultur 4609a9f26e8SHoratiu Vultur /* Adds a new MRP instance. 4619a9f26e8SHoratiu Vultur * note: called under rtnl_lock 4629a9f26e8SHoratiu Vultur */ 4639a9f26e8SHoratiu Vultur int br_mrp_add(struct net_bridge *br, struct br_mrp_instance *instance) 4649a9f26e8SHoratiu Vultur { 4659a9f26e8SHoratiu Vultur struct net_bridge_port *p; 4669a9f26e8SHoratiu Vultur struct br_mrp *mrp; 4679a9f26e8SHoratiu Vultur int err; 4689a9f26e8SHoratiu Vultur 4699a9f26e8SHoratiu Vultur /* If the ring exists, it is not possible to create another one with the 4709a9f26e8SHoratiu Vultur * same ring_id 4719a9f26e8SHoratiu Vultur */ 4729a9f26e8SHoratiu Vultur mrp = br_mrp_find_id(br, instance->ring_id); 4739a9f26e8SHoratiu Vultur if (mrp) 4749a9f26e8SHoratiu Vultur return -EINVAL; 4759a9f26e8SHoratiu Vultur 4769a9f26e8SHoratiu Vultur if (!br_mrp_get_port(br, instance->p_ifindex) || 4779a9f26e8SHoratiu Vultur !br_mrp_get_port(br, instance->s_ifindex)) 4789a9f26e8SHoratiu Vultur return -EINVAL; 4799a9f26e8SHoratiu Vultur 4807aa38018SHoratiu Vultur /* It is not possible to have the same port part of multiple rings */ 4817aa38018SHoratiu Vultur if (!br_mrp_unique_ifindex(br, instance->p_ifindex) || 4827aa38018SHoratiu Vultur !br_mrp_unique_ifindex(br, instance->s_ifindex)) 4837aa38018SHoratiu Vultur return -EINVAL; 4847aa38018SHoratiu Vultur 4859a9f26e8SHoratiu Vultur mrp = kzalloc(sizeof(*mrp), GFP_KERNEL); 4869a9f26e8SHoratiu Vultur if (!mrp) 4879a9f26e8SHoratiu Vultur return -ENOMEM; 4889a9f26e8SHoratiu Vultur 4899a9f26e8SHoratiu Vultur mrp->ring_id = instance->ring_id; 4904b3a61b0SHoratiu Vultur mrp->prio = instance->prio; 4919a9f26e8SHoratiu Vultur 4929a9f26e8SHoratiu Vultur p = br_mrp_get_port(br, instance->p_ifindex); 4939a9f26e8SHoratiu Vultur spin_lock_bh(&br->lock); 4949a9f26e8SHoratiu Vultur p->state = BR_STATE_FORWARDING; 4959a9f26e8SHoratiu Vultur p->flags |= BR_MRP_AWARE; 4969a9f26e8SHoratiu Vultur spin_unlock_bh(&br->lock); 4979a9f26e8SHoratiu Vultur rcu_assign_pointer(mrp->p_port, p); 4989a9f26e8SHoratiu Vultur 4999a9f26e8SHoratiu Vultur p = br_mrp_get_port(br, instance->s_ifindex); 5009a9f26e8SHoratiu Vultur spin_lock_bh(&br->lock); 5019a9f26e8SHoratiu Vultur p->state = BR_STATE_FORWARDING; 5029a9f26e8SHoratiu Vultur p->flags |= BR_MRP_AWARE; 5039a9f26e8SHoratiu Vultur spin_unlock_bh(&br->lock); 5049a9f26e8SHoratiu Vultur rcu_assign_pointer(mrp->s_port, p); 5059a9f26e8SHoratiu Vultur 5060169b820SHoratiu Vultur if (hlist_empty(&br->mrp_list)) 50790c628ddSHenrik Bjoernlund br_add_frame(br, &mrp_frame_type); 50890c628ddSHenrik Bjoernlund 5099a9f26e8SHoratiu Vultur INIT_DELAYED_WORK(&mrp->test_work, br_mrp_test_work_expired); 510537ed567SHoratiu Vultur INIT_DELAYED_WORK(&mrp->in_test_work, br_mrp_in_test_work_expired); 5110169b820SHoratiu Vultur hlist_add_tail_rcu(&mrp->list, &br->mrp_list); 5129a9f26e8SHoratiu Vultur 5139a9f26e8SHoratiu Vultur err = br_mrp_switchdev_add(br, mrp); 5149a9f26e8SHoratiu Vultur if (err) 5159a9f26e8SHoratiu Vultur goto delete_mrp; 5169a9f26e8SHoratiu Vultur 5179a9f26e8SHoratiu Vultur return 0; 5189a9f26e8SHoratiu Vultur 5199a9f26e8SHoratiu Vultur delete_mrp: 5209a9f26e8SHoratiu Vultur br_mrp_del_impl(br, mrp); 5219a9f26e8SHoratiu Vultur 5229a9f26e8SHoratiu Vultur return err; 5239a9f26e8SHoratiu Vultur } 5249a9f26e8SHoratiu Vultur 5259a9f26e8SHoratiu Vultur /* Deletes the MRP instance from which the port is part of 5269a9f26e8SHoratiu Vultur * note: called under rtnl_lock 5279a9f26e8SHoratiu Vultur */ 5289a9f26e8SHoratiu Vultur void br_mrp_port_del(struct net_bridge *br, struct net_bridge_port *p) 5299a9f26e8SHoratiu Vultur { 5309a9f26e8SHoratiu Vultur struct br_mrp *mrp = br_mrp_find_port(br, p); 5319a9f26e8SHoratiu Vultur 5329a9f26e8SHoratiu Vultur /* If the port is not part of a MRP instance just bail out */ 5339a9f26e8SHoratiu Vultur if (!mrp) 5349a9f26e8SHoratiu Vultur return; 5359a9f26e8SHoratiu Vultur 5369a9f26e8SHoratiu Vultur br_mrp_del_impl(br, mrp); 5379a9f26e8SHoratiu Vultur } 5389a9f26e8SHoratiu Vultur 5399a9f26e8SHoratiu Vultur /* Deletes existing MRP instance based on ring_id 5409a9f26e8SHoratiu Vultur * note: called under rtnl_lock 5419a9f26e8SHoratiu Vultur */ 5429a9f26e8SHoratiu Vultur int br_mrp_del(struct net_bridge *br, struct br_mrp_instance *instance) 5439a9f26e8SHoratiu Vultur { 5449a9f26e8SHoratiu Vultur struct br_mrp *mrp = br_mrp_find_id(br, instance->ring_id); 5459a9f26e8SHoratiu Vultur 5469a9f26e8SHoratiu Vultur if (!mrp) 5479a9f26e8SHoratiu Vultur return -EINVAL; 5489a9f26e8SHoratiu Vultur 5499a9f26e8SHoratiu Vultur br_mrp_del_impl(br, mrp); 5509a9f26e8SHoratiu Vultur 5519a9f26e8SHoratiu Vultur return 0; 5529a9f26e8SHoratiu Vultur } 5539a9f26e8SHoratiu Vultur 5549a9f26e8SHoratiu Vultur /* Set port state, port state can be forwarding, blocked or disabled 5559a9f26e8SHoratiu Vultur * note: already called with rtnl_lock 5569a9f26e8SHoratiu Vultur */ 5579a9f26e8SHoratiu Vultur int br_mrp_set_port_state(struct net_bridge_port *p, 5589a9f26e8SHoratiu Vultur enum br_mrp_port_state_type state) 5599a9f26e8SHoratiu Vultur { 5609a9f26e8SHoratiu Vultur if (!p || !(p->flags & BR_MRP_AWARE)) 5619a9f26e8SHoratiu Vultur return -EINVAL; 5629a9f26e8SHoratiu Vultur 5639a9f26e8SHoratiu Vultur spin_lock_bh(&p->br->lock); 5649a9f26e8SHoratiu Vultur 5659a9f26e8SHoratiu Vultur if (state == BR_MRP_PORT_STATE_FORWARDING) 5669a9f26e8SHoratiu Vultur p->state = BR_STATE_FORWARDING; 5679a9f26e8SHoratiu Vultur else 5689a9f26e8SHoratiu Vultur p->state = BR_STATE_BLOCKING; 5699a9f26e8SHoratiu Vultur 5709a9f26e8SHoratiu Vultur spin_unlock_bh(&p->br->lock); 5719a9f26e8SHoratiu Vultur 5729a9f26e8SHoratiu Vultur br_mrp_port_switchdev_set_state(p, state); 5739a9f26e8SHoratiu Vultur 5749a9f26e8SHoratiu Vultur return 0; 5759a9f26e8SHoratiu Vultur } 5769a9f26e8SHoratiu Vultur 5779a9f26e8SHoratiu Vultur /* Set port role, port role can be primary or secondary 5789a9f26e8SHoratiu Vultur * note: already called with rtnl_lock 5799a9f26e8SHoratiu Vultur */ 5809a9f26e8SHoratiu Vultur int br_mrp_set_port_role(struct net_bridge_port *p, 58120f6a05eSHoratiu Vultur enum br_mrp_port_role_type role) 5829a9f26e8SHoratiu Vultur { 5839a9f26e8SHoratiu Vultur struct br_mrp *mrp; 5849a9f26e8SHoratiu Vultur 5859a9f26e8SHoratiu Vultur if (!p || !(p->flags & BR_MRP_AWARE)) 5869a9f26e8SHoratiu Vultur return -EINVAL; 5879a9f26e8SHoratiu Vultur 58820f6a05eSHoratiu Vultur mrp = br_mrp_find_port(p->br, p); 5899a9f26e8SHoratiu Vultur 5909a9f26e8SHoratiu Vultur if (!mrp) 5919a9f26e8SHoratiu Vultur return -EINVAL; 5929a9f26e8SHoratiu Vultur 5937882c895SHoratiu Vultur switch (role) { 5947882c895SHoratiu Vultur case BR_MRP_PORT_ROLE_PRIMARY: 5959a9f26e8SHoratiu Vultur rcu_assign_pointer(mrp->p_port, p); 5967882c895SHoratiu Vultur break; 5977882c895SHoratiu Vultur case BR_MRP_PORT_ROLE_SECONDARY: 5989a9f26e8SHoratiu Vultur rcu_assign_pointer(mrp->s_port, p); 5997882c895SHoratiu Vultur break; 6007882c895SHoratiu Vultur default: 6017882c895SHoratiu Vultur return -EINVAL; 6027882c895SHoratiu Vultur } 6039a9f26e8SHoratiu Vultur 60420f6a05eSHoratiu Vultur br_mrp_port_switchdev_set_role(p, role); 6059a9f26e8SHoratiu Vultur 6069a9f26e8SHoratiu Vultur return 0; 6079a9f26e8SHoratiu Vultur } 6089a9f26e8SHoratiu Vultur 6099a9f26e8SHoratiu Vultur /* Set ring state, ring state can be only Open or Closed 6109a9f26e8SHoratiu Vultur * note: already called with rtnl_lock 6119a9f26e8SHoratiu Vultur */ 6129a9f26e8SHoratiu Vultur int br_mrp_set_ring_state(struct net_bridge *br, 6139a9f26e8SHoratiu Vultur struct br_mrp_ring_state *state) 6149a9f26e8SHoratiu Vultur { 6159a9f26e8SHoratiu Vultur struct br_mrp *mrp = br_mrp_find_id(br, state->ring_id); 6169a9f26e8SHoratiu Vultur 6179a9f26e8SHoratiu Vultur if (!mrp) 6189a9f26e8SHoratiu Vultur return -EINVAL; 6199a9f26e8SHoratiu Vultur 6209a9f26e8SHoratiu Vultur if (mrp->ring_state == BR_MRP_RING_STATE_CLOSED && 6219a9f26e8SHoratiu Vultur state->ring_state != BR_MRP_RING_STATE_CLOSED) 6229a9f26e8SHoratiu Vultur mrp->ring_transitions++; 6239a9f26e8SHoratiu Vultur 6249a9f26e8SHoratiu Vultur mrp->ring_state = state->ring_state; 6259a9f26e8SHoratiu Vultur 6269a9f26e8SHoratiu Vultur br_mrp_switchdev_set_ring_state(br, mrp, state->ring_state); 6279a9f26e8SHoratiu Vultur 6289a9f26e8SHoratiu Vultur return 0; 6299a9f26e8SHoratiu Vultur } 6309a9f26e8SHoratiu Vultur 6319a9f26e8SHoratiu Vultur /* Set ring role, ring role can be only MRM(Media Redundancy Manager) or 6329a9f26e8SHoratiu Vultur * MRC(Media Redundancy Client). 6339a9f26e8SHoratiu Vultur * note: already called with rtnl_lock 6349a9f26e8SHoratiu Vultur */ 6359a9f26e8SHoratiu Vultur int br_mrp_set_ring_role(struct net_bridge *br, 6369a9f26e8SHoratiu Vultur struct br_mrp_ring_role *role) 6379a9f26e8SHoratiu Vultur { 6389a9f26e8SHoratiu Vultur struct br_mrp *mrp = br_mrp_find_id(br, role->ring_id); 6399a9f26e8SHoratiu Vultur int err; 6409a9f26e8SHoratiu Vultur 6419a9f26e8SHoratiu Vultur if (!mrp) 6429a9f26e8SHoratiu Vultur return -EINVAL; 6439a9f26e8SHoratiu Vultur 6449a9f26e8SHoratiu Vultur mrp->ring_role = role->ring_role; 6459a9f26e8SHoratiu Vultur 6469a9f26e8SHoratiu Vultur /* If there is an error just bailed out */ 6479a9f26e8SHoratiu Vultur err = br_mrp_switchdev_set_ring_role(br, mrp, role->ring_role); 6489a9f26e8SHoratiu Vultur if (err && err != -EOPNOTSUPP) 6499a9f26e8SHoratiu Vultur return err; 6509a9f26e8SHoratiu Vultur 6519a9f26e8SHoratiu Vultur /* Now detect if the HW actually applied the role or not. If the HW 6529a9f26e8SHoratiu Vultur * applied the role it means that the SW will not to do those operations 6539a9f26e8SHoratiu Vultur * anymore. For example if the role ir MRM then the HW will notify the 6549a9f26e8SHoratiu Vultur * SW when ring is open, but if the is not pushed to the HW the SW will 6559a9f26e8SHoratiu Vultur * need to detect when the ring is open 6569a9f26e8SHoratiu Vultur */ 6579a9f26e8SHoratiu Vultur mrp->ring_role_offloaded = err == -EOPNOTSUPP ? 0 : 1; 6589a9f26e8SHoratiu Vultur 6599a9f26e8SHoratiu Vultur return 0; 6609a9f26e8SHoratiu Vultur } 6619a9f26e8SHoratiu Vultur 662c6676e7dSHoratiu Vultur /* Start to generate or monitor MRP test frames, the frames are generated by 663c6676e7dSHoratiu Vultur * HW and if it fails, they are generated by the SW. 6649a9f26e8SHoratiu Vultur * note: already called with rtnl_lock 6659a9f26e8SHoratiu Vultur */ 6669a9f26e8SHoratiu Vultur int br_mrp_start_test(struct net_bridge *br, 6679a9f26e8SHoratiu Vultur struct br_mrp_start_test *test) 6689a9f26e8SHoratiu Vultur { 6699a9f26e8SHoratiu Vultur struct br_mrp *mrp = br_mrp_find_id(br, test->ring_id); 6709a9f26e8SHoratiu Vultur 6719a9f26e8SHoratiu Vultur if (!mrp) 6729a9f26e8SHoratiu Vultur return -EINVAL; 6739a9f26e8SHoratiu Vultur 674c6676e7dSHoratiu Vultur /* Try to push it to the HW and if it fails then continue with SW 675c6676e7dSHoratiu Vultur * implementation and if that also fails then return error. 6769a9f26e8SHoratiu Vultur */ 6779a9f26e8SHoratiu Vultur if (!br_mrp_switchdev_send_ring_test(br, mrp, test->interval, 678c6676e7dSHoratiu Vultur test->max_miss, test->period, 679c6676e7dSHoratiu Vultur test->monitor)) 6809a9f26e8SHoratiu Vultur return 0; 6819a9f26e8SHoratiu Vultur 6829a9f26e8SHoratiu Vultur mrp->test_interval = test->interval; 6839a9f26e8SHoratiu Vultur mrp->test_end = jiffies + usecs_to_jiffies(test->period); 6849a9f26e8SHoratiu Vultur mrp->test_max_miss = test->max_miss; 685c6676e7dSHoratiu Vultur mrp->test_monitor = test->monitor; 6869a9f26e8SHoratiu Vultur mrp->test_count_miss = 0; 6879a9f26e8SHoratiu Vultur queue_delayed_work(system_wq, &mrp->test_work, 6889a9f26e8SHoratiu Vultur usecs_to_jiffies(test->interval)); 6899a9f26e8SHoratiu Vultur 6909a9f26e8SHoratiu Vultur return 0; 6919a9f26e8SHoratiu Vultur } 6929a9f26e8SHoratiu Vultur 693537ed567SHoratiu Vultur /* Set in state, int state can be only Open or Closed 694537ed567SHoratiu Vultur * note: already called with rtnl_lock 695537ed567SHoratiu Vultur */ 696537ed567SHoratiu Vultur int br_mrp_set_in_state(struct net_bridge *br, struct br_mrp_in_state *state) 697537ed567SHoratiu Vultur { 698537ed567SHoratiu Vultur struct br_mrp *mrp = br_mrp_find_in_id(br, state->in_id); 699537ed567SHoratiu Vultur 700537ed567SHoratiu Vultur if (!mrp) 701537ed567SHoratiu Vultur return -EINVAL; 702537ed567SHoratiu Vultur 703537ed567SHoratiu Vultur if (mrp->in_state == BR_MRP_IN_STATE_CLOSED && 704537ed567SHoratiu Vultur state->in_state != BR_MRP_IN_STATE_CLOSED) 705537ed567SHoratiu Vultur mrp->in_transitions++; 706537ed567SHoratiu Vultur 707537ed567SHoratiu Vultur mrp->in_state = state->in_state; 708537ed567SHoratiu Vultur 709537ed567SHoratiu Vultur br_mrp_switchdev_set_in_state(br, mrp, state->in_state); 710537ed567SHoratiu Vultur 711537ed567SHoratiu Vultur return 0; 712537ed567SHoratiu Vultur } 713537ed567SHoratiu Vultur 714537ed567SHoratiu Vultur /* Set in role, in role can be only MIM(Media Interconnection Manager) or 715537ed567SHoratiu Vultur * MIC(Media Interconnection Client). 716537ed567SHoratiu Vultur * note: already called with rtnl_lock 717537ed567SHoratiu Vultur */ 718537ed567SHoratiu Vultur int br_mrp_set_in_role(struct net_bridge *br, struct br_mrp_in_role *role) 719537ed567SHoratiu Vultur { 720537ed567SHoratiu Vultur struct br_mrp *mrp = br_mrp_find_id(br, role->ring_id); 721537ed567SHoratiu Vultur struct net_bridge_port *p; 722537ed567SHoratiu Vultur int err; 723537ed567SHoratiu Vultur 724537ed567SHoratiu Vultur if (!mrp) 725537ed567SHoratiu Vultur return -EINVAL; 726537ed567SHoratiu Vultur 727537ed567SHoratiu Vultur if (!br_mrp_get_port(br, role->i_ifindex)) 728537ed567SHoratiu Vultur return -EINVAL; 729537ed567SHoratiu Vultur 730537ed567SHoratiu Vultur if (role->in_role == BR_MRP_IN_ROLE_DISABLED) { 731537ed567SHoratiu Vultur u8 state; 732537ed567SHoratiu Vultur 733537ed567SHoratiu Vultur /* It is not allowed to disable a port that doesn't exist */ 734537ed567SHoratiu Vultur p = rtnl_dereference(mrp->i_port); 735537ed567SHoratiu Vultur if (!p) 736537ed567SHoratiu Vultur return -EINVAL; 737537ed567SHoratiu Vultur 738537ed567SHoratiu Vultur /* Stop the generating MRP_InTest frames */ 739537ed567SHoratiu Vultur cancel_delayed_work_sync(&mrp->in_test_work); 740537ed567SHoratiu Vultur br_mrp_switchdev_send_in_test(br, mrp, 0, 0, 0); 741537ed567SHoratiu Vultur 742537ed567SHoratiu Vultur /* Remove the port */ 743537ed567SHoratiu Vultur spin_lock_bh(&br->lock); 744537ed567SHoratiu Vultur state = netif_running(br->dev) ? 745537ed567SHoratiu Vultur BR_STATE_FORWARDING : BR_STATE_DISABLED; 746537ed567SHoratiu Vultur p->state = state; 747537ed567SHoratiu Vultur p->flags &= ~BR_MRP_AWARE; 748537ed567SHoratiu Vultur spin_unlock_bh(&br->lock); 749537ed567SHoratiu Vultur br_mrp_port_switchdev_set_state(p, state); 750537ed567SHoratiu Vultur rcu_assign_pointer(mrp->i_port, NULL); 751537ed567SHoratiu Vultur 752537ed567SHoratiu Vultur mrp->in_role = role->in_role; 753537ed567SHoratiu Vultur mrp->in_id = 0; 754537ed567SHoratiu Vultur 755537ed567SHoratiu Vultur return 0; 756537ed567SHoratiu Vultur } 757537ed567SHoratiu Vultur 758537ed567SHoratiu Vultur /* It is not possible to have the same port part of multiple rings */ 759537ed567SHoratiu Vultur if (!br_mrp_unique_ifindex(br, role->i_ifindex)) 760537ed567SHoratiu Vultur return -EINVAL; 761537ed567SHoratiu Vultur 762537ed567SHoratiu Vultur /* It is not allowed to set a different interconnect port if the mrp 763537ed567SHoratiu Vultur * instance has already one. First it needs to be disabled and after 764537ed567SHoratiu Vultur * that set the new port 765537ed567SHoratiu Vultur */ 766537ed567SHoratiu Vultur if (rcu_access_pointer(mrp->i_port)) 767537ed567SHoratiu Vultur return -EINVAL; 768537ed567SHoratiu Vultur 769537ed567SHoratiu Vultur p = br_mrp_get_port(br, role->i_ifindex); 770537ed567SHoratiu Vultur spin_lock_bh(&br->lock); 771537ed567SHoratiu Vultur p->state = BR_STATE_FORWARDING; 772537ed567SHoratiu Vultur p->flags |= BR_MRP_AWARE; 773537ed567SHoratiu Vultur spin_unlock_bh(&br->lock); 774537ed567SHoratiu Vultur rcu_assign_pointer(mrp->i_port, p); 775537ed567SHoratiu Vultur 776537ed567SHoratiu Vultur mrp->in_role = role->in_role; 777537ed567SHoratiu Vultur mrp->in_id = role->in_id; 778537ed567SHoratiu Vultur 779537ed567SHoratiu Vultur /* If there is an error just bailed out */ 780537ed567SHoratiu Vultur err = br_mrp_switchdev_set_in_role(br, mrp, role->in_id, 781537ed567SHoratiu Vultur role->ring_id, role->in_role); 782537ed567SHoratiu Vultur if (err && err != -EOPNOTSUPP) 783537ed567SHoratiu Vultur return err; 784537ed567SHoratiu Vultur 785537ed567SHoratiu Vultur /* Now detect if the HW actually applied the role or not. If the HW 786537ed567SHoratiu Vultur * applied the role it means that the SW will not to do those operations 787537ed567SHoratiu Vultur * anymore. For example if the role is MIM then the HW will notify the 788537ed567SHoratiu Vultur * SW when interconnect ring is open, but if the is not pushed to the HW 789537ed567SHoratiu Vultur * the SW will need to detect when the interconnect ring is open. 790537ed567SHoratiu Vultur */ 791537ed567SHoratiu Vultur mrp->in_role_offloaded = err == -EOPNOTSUPP ? 0 : 1; 792537ed567SHoratiu Vultur 793537ed567SHoratiu Vultur return 0; 794537ed567SHoratiu Vultur } 795537ed567SHoratiu Vultur 796537ed567SHoratiu Vultur /* Start to generate MRP_InTest frames, the frames are generated by 797537ed567SHoratiu Vultur * HW and if it fails, they are generated by the SW. 798537ed567SHoratiu Vultur * note: already called with rtnl_lock 799537ed567SHoratiu Vultur */ 800537ed567SHoratiu Vultur int br_mrp_start_in_test(struct net_bridge *br, 801537ed567SHoratiu Vultur struct br_mrp_start_in_test *in_test) 802537ed567SHoratiu Vultur { 803537ed567SHoratiu Vultur struct br_mrp *mrp = br_mrp_find_in_id(br, in_test->in_id); 804537ed567SHoratiu Vultur 805537ed567SHoratiu Vultur if (!mrp) 806537ed567SHoratiu Vultur return -EINVAL; 807537ed567SHoratiu Vultur 808537ed567SHoratiu Vultur if (mrp->in_role != BR_MRP_IN_ROLE_MIM) 809537ed567SHoratiu Vultur return -EINVAL; 810537ed567SHoratiu Vultur 811537ed567SHoratiu Vultur /* Try to push it to the HW and if it fails then continue with SW 812537ed567SHoratiu Vultur * implementation and if that also fails then return error. 813537ed567SHoratiu Vultur */ 814537ed567SHoratiu Vultur if (!br_mrp_switchdev_send_in_test(br, mrp, in_test->interval, 815537ed567SHoratiu Vultur in_test->max_miss, in_test->period)) 816537ed567SHoratiu Vultur return 0; 817537ed567SHoratiu Vultur 818537ed567SHoratiu Vultur mrp->in_test_interval = in_test->interval; 819537ed567SHoratiu Vultur mrp->in_test_end = jiffies + usecs_to_jiffies(in_test->period); 820537ed567SHoratiu Vultur mrp->in_test_max_miss = in_test->max_miss; 821537ed567SHoratiu Vultur mrp->in_test_count_miss = 0; 822537ed567SHoratiu Vultur queue_delayed_work(system_wq, &mrp->in_test_work, 823537ed567SHoratiu Vultur usecs_to_jiffies(in_test->interval)); 824537ed567SHoratiu Vultur 825537ed567SHoratiu Vultur return 0; 826537ed567SHoratiu Vultur } 827537ed567SHoratiu Vultur 828*efb5b338SMenglong Dong /* Determine if the frame type is a ring frame */ 829537ed567SHoratiu Vultur static bool br_mrp_ring_frame(struct sk_buff *skb) 830537ed567SHoratiu Vultur { 831537ed567SHoratiu Vultur const struct br_mrp_tlv_hdr *hdr; 832537ed567SHoratiu Vultur struct br_mrp_tlv_hdr _hdr; 833537ed567SHoratiu Vultur 834537ed567SHoratiu Vultur hdr = skb_header_pointer(skb, sizeof(uint16_t), sizeof(_hdr), &_hdr); 835537ed567SHoratiu Vultur if (!hdr) 836537ed567SHoratiu Vultur return false; 837537ed567SHoratiu Vultur 838537ed567SHoratiu Vultur if (hdr->type == BR_MRP_TLV_HEADER_RING_TEST || 839537ed567SHoratiu Vultur hdr->type == BR_MRP_TLV_HEADER_RING_TOPO || 840537ed567SHoratiu Vultur hdr->type == BR_MRP_TLV_HEADER_RING_LINK_DOWN || 841537ed567SHoratiu Vultur hdr->type == BR_MRP_TLV_HEADER_RING_LINK_UP || 842537ed567SHoratiu Vultur hdr->type == BR_MRP_TLV_HEADER_OPTION) 843537ed567SHoratiu Vultur return true; 844537ed567SHoratiu Vultur 845537ed567SHoratiu Vultur return false; 846537ed567SHoratiu Vultur } 847537ed567SHoratiu Vultur 848*efb5b338SMenglong Dong /* Determine if the frame type is an interconnect frame */ 849537ed567SHoratiu Vultur static bool br_mrp_in_frame(struct sk_buff *skb) 850537ed567SHoratiu Vultur { 851537ed567SHoratiu Vultur const struct br_mrp_tlv_hdr *hdr; 852537ed567SHoratiu Vultur struct br_mrp_tlv_hdr _hdr; 853537ed567SHoratiu Vultur 854537ed567SHoratiu Vultur hdr = skb_header_pointer(skb, sizeof(uint16_t), sizeof(_hdr), &_hdr); 855537ed567SHoratiu Vultur if (!hdr) 856537ed567SHoratiu Vultur return false; 857537ed567SHoratiu Vultur 858537ed567SHoratiu Vultur if (hdr->type == BR_MRP_TLV_HEADER_IN_TEST || 859537ed567SHoratiu Vultur hdr->type == BR_MRP_TLV_HEADER_IN_TOPO || 860537ed567SHoratiu Vultur hdr->type == BR_MRP_TLV_HEADER_IN_LINK_DOWN || 861bfd04232SHoratiu Vultur hdr->type == BR_MRP_TLV_HEADER_IN_LINK_UP || 862bfd04232SHoratiu Vultur hdr->type == BR_MRP_TLV_HEADER_IN_LINK_STATUS) 863537ed567SHoratiu Vultur return true; 864537ed567SHoratiu Vultur 865537ed567SHoratiu Vultur return false; 866537ed567SHoratiu Vultur } 867537ed567SHoratiu Vultur 8689a9f26e8SHoratiu Vultur /* Process only MRP Test frame. All the other MRP frames are processed by 8699a9f26e8SHoratiu Vultur * userspace application 8709a9f26e8SHoratiu Vultur * note: already called with rcu_read_lock 8719a9f26e8SHoratiu Vultur */ 8729a9f26e8SHoratiu Vultur static void br_mrp_mrm_process(struct br_mrp *mrp, struct net_bridge_port *port, 8739a9f26e8SHoratiu Vultur struct sk_buff *skb) 8749a9f26e8SHoratiu Vultur { 8759a9f26e8SHoratiu Vultur const struct br_mrp_tlv_hdr *hdr; 8769a9f26e8SHoratiu Vultur struct br_mrp_tlv_hdr _hdr; 8779a9f26e8SHoratiu Vultur 8789a9f26e8SHoratiu Vultur /* Each MRP header starts with a version field which is 16 bits. 8799a9f26e8SHoratiu Vultur * Therefore skip the version and get directly the TLV header. 8809a9f26e8SHoratiu Vultur */ 8819a9f26e8SHoratiu Vultur hdr = skb_header_pointer(skb, sizeof(uint16_t), sizeof(_hdr), &_hdr); 8829a9f26e8SHoratiu Vultur if (!hdr) 8839a9f26e8SHoratiu Vultur return; 8849a9f26e8SHoratiu Vultur 8859a9f26e8SHoratiu Vultur if (hdr->type != BR_MRP_TLV_HEADER_RING_TEST) 8869a9f26e8SHoratiu Vultur return; 8879a9f26e8SHoratiu Vultur 8889a9f26e8SHoratiu Vultur mrp->test_count_miss = 0; 8899a9f26e8SHoratiu Vultur 8909a9f26e8SHoratiu Vultur /* Notify the userspace that the ring is closed only when the ring is 8919a9f26e8SHoratiu Vultur * not closed 8929a9f26e8SHoratiu Vultur */ 8939a9f26e8SHoratiu Vultur if (mrp->ring_state != BR_MRP_RING_STATE_CLOSED) 8944cc625c6SHoratiu Vultur br_mrp_ring_port_open(port->dev, false); 8959a9f26e8SHoratiu Vultur } 8969a9f26e8SHoratiu Vultur 897*efb5b338SMenglong Dong /* Determine if the test hdr has a better priority than the node */ 898c6676e7dSHoratiu Vultur static bool br_mrp_test_better_than_own(struct br_mrp *mrp, 899c6676e7dSHoratiu Vultur struct net_bridge *br, 900c6676e7dSHoratiu Vultur const struct br_mrp_ring_test_hdr *hdr) 901c6676e7dSHoratiu Vultur { 902c6676e7dSHoratiu Vultur u16 prio = be16_to_cpu(hdr->prio); 903c6676e7dSHoratiu Vultur 904c6676e7dSHoratiu Vultur if (prio < mrp->prio || 905c6676e7dSHoratiu Vultur (prio == mrp->prio && 906c6676e7dSHoratiu Vultur ether_addr_to_u64(hdr->sa) < ether_addr_to_u64(br->dev->dev_addr))) 907c6676e7dSHoratiu Vultur return true; 908c6676e7dSHoratiu Vultur 909c6676e7dSHoratiu Vultur return false; 910c6676e7dSHoratiu Vultur } 911c6676e7dSHoratiu Vultur 912c6676e7dSHoratiu Vultur /* Process only MRP Test frame. All the other MRP frames are processed by 913c6676e7dSHoratiu Vultur * userspace application 914c6676e7dSHoratiu Vultur * note: already called with rcu_read_lock 915c6676e7dSHoratiu Vultur */ 916c6676e7dSHoratiu Vultur static void br_mrp_mra_process(struct br_mrp *mrp, struct net_bridge *br, 917c6676e7dSHoratiu Vultur struct net_bridge_port *port, 918c6676e7dSHoratiu Vultur struct sk_buff *skb) 919c6676e7dSHoratiu Vultur { 920c6676e7dSHoratiu Vultur const struct br_mrp_ring_test_hdr *test_hdr; 921c6676e7dSHoratiu Vultur struct br_mrp_ring_test_hdr _test_hdr; 922c6676e7dSHoratiu Vultur const struct br_mrp_tlv_hdr *hdr; 923c6676e7dSHoratiu Vultur struct br_mrp_tlv_hdr _hdr; 924c6676e7dSHoratiu Vultur 925c6676e7dSHoratiu Vultur /* Each MRP header starts with a version field which is 16 bits. 926c6676e7dSHoratiu Vultur * Therefore skip the version and get directly the TLV header. 927c6676e7dSHoratiu Vultur */ 928c6676e7dSHoratiu Vultur hdr = skb_header_pointer(skb, sizeof(uint16_t), sizeof(_hdr), &_hdr); 929c6676e7dSHoratiu Vultur if (!hdr) 930c6676e7dSHoratiu Vultur return; 931c6676e7dSHoratiu Vultur 932c6676e7dSHoratiu Vultur if (hdr->type != BR_MRP_TLV_HEADER_RING_TEST) 933c6676e7dSHoratiu Vultur return; 934c6676e7dSHoratiu Vultur 935c6676e7dSHoratiu Vultur test_hdr = skb_header_pointer(skb, sizeof(uint16_t) + sizeof(_hdr), 936c6676e7dSHoratiu Vultur sizeof(_test_hdr), &_test_hdr); 937c6676e7dSHoratiu Vultur if (!test_hdr) 938c6676e7dSHoratiu Vultur return; 939c6676e7dSHoratiu Vultur 940c6676e7dSHoratiu Vultur /* Only frames that have a better priority than the node will 941c6676e7dSHoratiu Vultur * clear the miss counter because otherwise the node will need to behave 942c6676e7dSHoratiu Vultur * as MRM. 943c6676e7dSHoratiu Vultur */ 944c6676e7dSHoratiu Vultur if (br_mrp_test_better_than_own(mrp, br, test_hdr)) 945c6676e7dSHoratiu Vultur mrp->test_count_miss = 0; 946c6676e7dSHoratiu Vultur } 947c6676e7dSHoratiu Vultur 948537ed567SHoratiu Vultur /* Process only MRP InTest frame. All the other MRP frames are processed by 949537ed567SHoratiu Vultur * userspace application 950537ed567SHoratiu Vultur * note: already called with rcu_read_lock 951537ed567SHoratiu Vultur */ 952537ed567SHoratiu Vultur static bool br_mrp_mim_process(struct br_mrp *mrp, struct net_bridge_port *port, 953537ed567SHoratiu Vultur struct sk_buff *skb) 954537ed567SHoratiu Vultur { 955537ed567SHoratiu Vultur const struct br_mrp_in_test_hdr *in_hdr; 956537ed567SHoratiu Vultur struct br_mrp_in_test_hdr _in_hdr; 957537ed567SHoratiu Vultur const struct br_mrp_tlv_hdr *hdr; 958537ed567SHoratiu Vultur struct br_mrp_tlv_hdr _hdr; 959537ed567SHoratiu Vultur 960537ed567SHoratiu Vultur /* Each MRP header starts with a version field which is 16 bits. 961537ed567SHoratiu Vultur * Therefore skip the version and get directly the TLV header. 962537ed567SHoratiu Vultur */ 963537ed567SHoratiu Vultur hdr = skb_header_pointer(skb, sizeof(uint16_t), sizeof(_hdr), &_hdr); 964537ed567SHoratiu Vultur if (!hdr) 965537ed567SHoratiu Vultur return false; 966537ed567SHoratiu Vultur 967537ed567SHoratiu Vultur /* The check for InTest frame type was already done */ 968537ed567SHoratiu Vultur in_hdr = skb_header_pointer(skb, sizeof(uint16_t) + sizeof(_hdr), 969537ed567SHoratiu Vultur sizeof(_in_hdr), &_in_hdr); 970537ed567SHoratiu Vultur if (!in_hdr) 971537ed567SHoratiu Vultur return false; 972537ed567SHoratiu Vultur 973537ed567SHoratiu Vultur /* It needs to process only it's own InTest frames. */ 974537ed567SHoratiu Vultur if (mrp->in_id != ntohs(in_hdr->id)) 975537ed567SHoratiu Vultur return false; 976537ed567SHoratiu Vultur 977537ed567SHoratiu Vultur mrp->in_test_count_miss = 0; 978537ed567SHoratiu Vultur 979537ed567SHoratiu Vultur /* Notify the userspace that the ring is closed only when the ring is 980537ed567SHoratiu Vultur * not closed 981537ed567SHoratiu Vultur */ 982537ed567SHoratiu Vultur if (mrp->in_state != BR_MRP_IN_STATE_CLOSED) 983537ed567SHoratiu Vultur br_mrp_in_port_open(port->dev, false); 984537ed567SHoratiu Vultur 985537ed567SHoratiu Vultur return true; 986537ed567SHoratiu Vultur } 987537ed567SHoratiu Vultur 988537ed567SHoratiu Vultur /* Get the MRP frame type 989537ed567SHoratiu Vultur * note: already called with rcu_read_lock 990537ed567SHoratiu Vultur */ 991537ed567SHoratiu Vultur static u8 br_mrp_get_frame_type(struct sk_buff *skb) 992537ed567SHoratiu Vultur { 993537ed567SHoratiu Vultur const struct br_mrp_tlv_hdr *hdr; 994537ed567SHoratiu Vultur struct br_mrp_tlv_hdr _hdr; 995537ed567SHoratiu Vultur 996537ed567SHoratiu Vultur /* Each MRP header starts with a version field which is 16 bits. 997537ed567SHoratiu Vultur * Therefore skip the version and get directly the TLV header. 998537ed567SHoratiu Vultur */ 999537ed567SHoratiu Vultur hdr = skb_header_pointer(skb, sizeof(uint16_t), sizeof(_hdr), &_hdr); 1000537ed567SHoratiu Vultur if (!hdr) 1001537ed567SHoratiu Vultur return 0xff; 1002537ed567SHoratiu Vultur 1003537ed567SHoratiu Vultur return hdr->type; 1004537ed567SHoratiu Vultur } 1005537ed567SHoratiu Vultur 1006537ed567SHoratiu Vultur static bool br_mrp_mrm_behaviour(struct br_mrp *mrp) 1007537ed567SHoratiu Vultur { 1008537ed567SHoratiu Vultur if (mrp->ring_role == BR_MRP_RING_ROLE_MRM || 1009537ed567SHoratiu Vultur (mrp->ring_role == BR_MRP_RING_ROLE_MRA && !mrp->test_monitor)) 1010537ed567SHoratiu Vultur return true; 1011537ed567SHoratiu Vultur 1012537ed567SHoratiu Vultur return false; 1013537ed567SHoratiu Vultur } 1014537ed567SHoratiu Vultur 1015537ed567SHoratiu Vultur static bool br_mrp_mrc_behaviour(struct br_mrp *mrp) 1016537ed567SHoratiu Vultur { 1017537ed567SHoratiu Vultur if (mrp->ring_role == BR_MRP_RING_ROLE_MRC || 1018537ed567SHoratiu Vultur (mrp->ring_role == BR_MRP_RING_ROLE_MRA && mrp->test_monitor)) 1019537ed567SHoratiu Vultur return true; 1020537ed567SHoratiu Vultur 1021537ed567SHoratiu Vultur return false; 1022537ed567SHoratiu Vultur } 1023537ed567SHoratiu Vultur 1024537ed567SHoratiu Vultur /* This will just forward the frame to the other mrp ring ports, depending on 1025537ed567SHoratiu Vultur * the frame type, ring role and interconnect role 10269a9f26e8SHoratiu Vultur * note: already called with rcu_read_lock 10279a9f26e8SHoratiu Vultur */ 10289a9f26e8SHoratiu Vultur static int br_mrp_rcv(struct net_bridge_port *p, 10299a9f26e8SHoratiu Vultur struct sk_buff *skb, struct net_device *dev) 10309a9f26e8SHoratiu Vultur { 1031537ed567SHoratiu Vultur struct net_bridge_port *p_port, *s_port, *i_port = NULL; 1032537ed567SHoratiu Vultur struct net_bridge_port *p_dst, *s_dst, *i_dst = NULL; 10339a9f26e8SHoratiu Vultur struct net_bridge *br; 10349a9f26e8SHoratiu Vultur struct br_mrp *mrp; 10359a9f26e8SHoratiu Vultur 10369a9f26e8SHoratiu Vultur /* If port is disabled don't accept any frames */ 10379a9f26e8SHoratiu Vultur if (p->state == BR_STATE_DISABLED) 10389a9f26e8SHoratiu Vultur return 0; 10399a9f26e8SHoratiu Vultur 10409a9f26e8SHoratiu Vultur br = p->br; 10419a9f26e8SHoratiu Vultur mrp = br_mrp_find_port(br, p); 10429a9f26e8SHoratiu Vultur if (unlikely(!mrp)) 10439a9f26e8SHoratiu Vultur return 0; 10449a9f26e8SHoratiu Vultur 10459a9f26e8SHoratiu Vultur p_port = rcu_dereference(mrp->p_port); 10469a9f26e8SHoratiu Vultur if (!p_port) 10479a9f26e8SHoratiu Vultur return 0; 1048537ed567SHoratiu Vultur p_dst = p_port; 10499a9f26e8SHoratiu Vultur 10509a9f26e8SHoratiu Vultur s_port = rcu_dereference(mrp->s_port); 10519a9f26e8SHoratiu Vultur if (!s_port) 10529a9f26e8SHoratiu Vultur return 0; 1053537ed567SHoratiu Vultur s_dst = s_port; 10549a9f26e8SHoratiu Vultur 1055537ed567SHoratiu Vultur /* If the frame is a ring frame then it is not required to check the 1056537ed567SHoratiu Vultur * interconnect role and ports to process or forward the frame 1057537ed567SHoratiu Vultur */ 1058537ed567SHoratiu Vultur if (br_mrp_ring_frame(skb)) { 10599a9f26e8SHoratiu Vultur /* If the role is MRM then don't forward the frames */ 10609a9f26e8SHoratiu Vultur if (mrp->ring_role == BR_MRP_RING_ROLE_MRM) { 10619a9f26e8SHoratiu Vultur br_mrp_mrm_process(mrp, p, skb); 1062537ed567SHoratiu Vultur goto no_forward; 10639a9f26e8SHoratiu Vultur } 10649a9f26e8SHoratiu Vultur 1065537ed567SHoratiu Vultur /* If the role is MRA then don't forward the frames if it 1066537ed567SHoratiu Vultur * behaves as MRM node 1067c6676e7dSHoratiu Vultur */ 1068c6676e7dSHoratiu Vultur if (mrp->ring_role == BR_MRP_RING_ROLE_MRA) { 1069c6676e7dSHoratiu Vultur if (!mrp->test_monitor) { 1070c6676e7dSHoratiu Vultur br_mrp_mrm_process(mrp, p, skb); 1071537ed567SHoratiu Vultur goto no_forward; 1072c6676e7dSHoratiu Vultur } 1073c6676e7dSHoratiu Vultur 1074c6676e7dSHoratiu Vultur br_mrp_mra_process(mrp, br, p, skb); 1075c6676e7dSHoratiu Vultur } 1076c6676e7dSHoratiu Vultur 1077537ed567SHoratiu Vultur goto forward; 1078537ed567SHoratiu Vultur } 10799a9f26e8SHoratiu Vultur 1080537ed567SHoratiu Vultur if (br_mrp_in_frame(skb)) { 1081537ed567SHoratiu Vultur u8 in_type = br_mrp_get_frame_type(skb); 10829a9f26e8SHoratiu Vultur 1083537ed567SHoratiu Vultur i_port = rcu_dereference(mrp->i_port); 1084537ed567SHoratiu Vultur i_dst = i_port; 10859a9f26e8SHoratiu Vultur 1086537ed567SHoratiu Vultur /* If the ring port is in block state it should not forward 1087537ed567SHoratiu Vultur * In_Test frames 1088537ed567SHoratiu Vultur */ 1089537ed567SHoratiu Vultur if (br_mrp_is_ring_port(p_port, s_port, p) && 1090537ed567SHoratiu Vultur p->state == BR_STATE_BLOCKING && 1091537ed567SHoratiu Vultur in_type == BR_MRP_TLV_HEADER_IN_TEST) 1092537ed567SHoratiu Vultur goto no_forward; 10939a9f26e8SHoratiu Vultur 1094537ed567SHoratiu Vultur /* Nodes that behaves as MRM needs to stop forwarding the 1095537ed567SHoratiu Vultur * frames in case the ring is closed, otherwise will be a loop. 1096537ed567SHoratiu Vultur * In this case the frame is no forward between the ring ports. 1097537ed567SHoratiu Vultur */ 1098537ed567SHoratiu Vultur if (br_mrp_mrm_behaviour(mrp) && 1099537ed567SHoratiu Vultur br_mrp_is_ring_port(p_port, s_port, p) && 1100537ed567SHoratiu Vultur (s_port->state != BR_STATE_FORWARDING || 1101537ed567SHoratiu Vultur p_port->state != BR_STATE_FORWARDING)) { 1102537ed567SHoratiu Vultur p_dst = NULL; 1103537ed567SHoratiu Vultur s_dst = NULL; 1104537ed567SHoratiu Vultur } 1105537ed567SHoratiu Vultur 1106537ed567SHoratiu Vultur /* A node that behaves as MRC and doesn't have a interconnect 1107537ed567SHoratiu Vultur * role then it should forward all frames between the ring ports 1108537ed567SHoratiu Vultur * because it doesn't have an interconnect port 1109537ed567SHoratiu Vultur */ 1110537ed567SHoratiu Vultur if (br_mrp_mrc_behaviour(mrp) && 1111537ed567SHoratiu Vultur mrp->in_role == BR_MRP_IN_ROLE_DISABLED) 1112537ed567SHoratiu Vultur goto forward; 1113537ed567SHoratiu Vultur 1114537ed567SHoratiu Vultur if (mrp->in_role == BR_MRP_IN_ROLE_MIM) { 1115537ed567SHoratiu Vultur if (in_type == BR_MRP_TLV_HEADER_IN_TEST) { 1116537ed567SHoratiu Vultur /* MIM should not forward it's own InTest 1117537ed567SHoratiu Vultur * frames 1118537ed567SHoratiu Vultur */ 1119537ed567SHoratiu Vultur if (br_mrp_mim_process(mrp, p, skb)) { 1120537ed567SHoratiu Vultur goto no_forward; 1121537ed567SHoratiu Vultur } else { 1122537ed567SHoratiu Vultur if (br_mrp_is_ring_port(p_port, s_port, 1123537ed567SHoratiu Vultur p)) 1124537ed567SHoratiu Vultur i_dst = NULL; 1125537ed567SHoratiu Vultur 1126537ed567SHoratiu Vultur if (br_mrp_is_in_port(i_port, p)) 1127537ed567SHoratiu Vultur goto no_forward; 1128537ed567SHoratiu Vultur } 1129537ed567SHoratiu Vultur } else { 1130bfd04232SHoratiu Vultur /* MIM should forward IntLinkChange/Status and 1131537ed567SHoratiu Vultur * IntTopoChange between ring ports but MIM 1132bfd04232SHoratiu Vultur * should not forward IntLinkChange/Status and 1133537ed567SHoratiu Vultur * IntTopoChange if the frame was received at 1134537ed567SHoratiu Vultur * the interconnect port 1135537ed567SHoratiu Vultur */ 1136537ed567SHoratiu Vultur if (br_mrp_is_ring_port(p_port, s_port, p)) 1137537ed567SHoratiu Vultur i_dst = NULL; 1138537ed567SHoratiu Vultur 1139537ed567SHoratiu Vultur if (br_mrp_is_in_port(i_port, p)) 1140537ed567SHoratiu Vultur goto no_forward; 1141537ed567SHoratiu Vultur } 1142537ed567SHoratiu Vultur } 1143537ed567SHoratiu Vultur 1144537ed567SHoratiu Vultur if (mrp->in_role == BR_MRP_IN_ROLE_MIC) { 1145537ed567SHoratiu Vultur /* MIC should forward InTest frames on all ports 1146537ed567SHoratiu Vultur * regardless of the received port 1147537ed567SHoratiu Vultur */ 1148537ed567SHoratiu Vultur if (in_type == BR_MRP_TLV_HEADER_IN_TEST) 1149537ed567SHoratiu Vultur goto forward; 1150537ed567SHoratiu Vultur 1151537ed567SHoratiu Vultur /* MIC should forward IntLinkChange frames only if they 1152537ed567SHoratiu Vultur * are received on ring ports to all the ports 1153537ed567SHoratiu Vultur */ 1154537ed567SHoratiu Vultur if (br_mrp_is_ring_port(p_port, s_port, p) && 1155537ed567SHoratiu Vultur (in_type == BR_MRP_TLV_HEADER_IN_LINK_UP || 1156537ed567SHoratiu Vultur in_type == BR_MRP_TLV_HEADER_IN_LINK_DOWN)) 1157537ed567SHoratiu Vultur goto forward; 1158537ed567SHoratiu Vultur 1159bfd04232SHoratiu Vultur /* MIC should forward IntLinkStatus frames only to 1160bfd04232SHoratiu Vultur * interconnect port if it was received on a ring port. 1161bfd04232SHoratiu Vultur * If it is received on interconnect port then, it 1162bfd04232SHoratiu Vultur * should be forward on both ring ports 1163bfd04232SHoratiu Vultur */ 1164bfd04232SHoratiu Vultur if (br_mrp_is_ring_port(p_port, s_port, p) && 1165bfd04232SHoratiu Vultur in_type == BR_MRP_TLV_HEADER_IN_LINK_STATUS) { 1166bfd04232SHoratiu Vultur p_dst = NULL; 1167bfd04232SHoratiu Vultur s_dst = NULL; 1168bfd04232SHoratiu Vultur } 1169bfd04232SHoratiu Vultur 1170537ed567SHoratiu Vultur /* Should forward the InTopo frames only between the 1171537ed567SHoratiu Vultur * ring ports 1172537ed567SHoratiu Vultur */ 1173537ed567SHoratiu Vultur if (in_type == BR_MRP_TLV_HEADER_IN_TOPO) { 1174537ed567SHoratiu Vultur i_dst = NULL; 1175537ed567SHoratiu Vultur goto forward; 1176537ed567SHoratiu Vultur } 1177537ed567SHoratiu Vultur 1178537ed567SHoratiu Vultur /* In all the other cases don't forward the frames */ 1179537ed567SHoratiu Vultur goto no_forward; 1180537ed567SHoratiu Vultur } 1181537ed567SHoratiu Vultur } 1182537ed567SHoratiu Vultur 1183537ed567SHoratiu Vultur forward: 1184537ed567SHoratiu Vultur if (p_dst) 1185537ed567SHoratiu Vultur br_forward(p_dst, skb, true, false); 1186537ed567SHoratiu Vultur if (s_dst) 1187537ed567SHoratiu Vultur br_forward(s_dst, skb, true, false); 1188537ed567SHoratiu Vultur if (i_dst) 1189537ed567SHoratiu Vultur br_forward(i_dst, skb, true, false); 1190537ed567SHoratiu Vultur 1191537ed567SHoratiu Vultur no_forward: 11929a9f26e8SHoratiu Vultur return 1; 11939a9f26e8SHoratiu Vultur } 11949a9f26e8SHoratiu Vultur 11959a9f26e8SHoratiu Vultur /* Check if the frame was received on a port that is part of MRP ring 11969a9f26e8SHoratiu Vultur * and if the frame has MRP eth. In that case process the frame otherwise do 11979a9f26e8SHoratiu Vultur * normal forwarding. 11989a9f26e8SHoratiu Vultur * note: already called with rcu_read_lock 11999a9f26e8SHoratiu Vultur */ 120090c628ddSHenrik Bjoernlund static int br_mrp_process(struct net_bridge_port *p, struct sk_buff *skb) 12019a9f26e8SHoratiu Vultur { 12029a9f26e8SHoratiu Vultur /* If there is no MRP instance do normal forwarding */ 12039a9f26e8SHoratiu Vultur if (likely(!(p->flags & BR_MRP_AWARE))) 12049a9f26e8SHoratiu Vultur goto out; 12059a9f26e8SHoratiu Vultur 12069a9f26e8SHoratiu Vultur return br_mrp_rcv(p, skb, p->dev); 12079a9f26e8SHoratiu Vultur out: 12089a9f26e8SHoratiu Vultur return 0; 12099a9f26e8SHoratiu Vultur } 12109a9f26e8SHoratiu Vultur 12119a9f26e8SHoratiu Vultur bool br_mrp_enabled(struct net_bridge *br) 12129a9f26e8SHoratiu Vultur { 12130169b820SHoratiu Vultur return !hlist_empty(&br->mrp_list); 12149a9f26e8SHoratiu Vultur } 1215