Lines Matching +full:1 +full:br +full:- +full:100
1 // SPDX-License-Identifier: GPL-2.0-or-later
7 static struct br_cfm_mep *br_mep_find(struct net_bridge *br, u32 instance) in br_mep_find() argument
11 hlist_for_each_entry(mep, &br->mep_list, head) in br_mep_find()
12 if (mep->instance == instance) in br_mep_find()
18 static struct br_cfm_mep *br_mep_find_ifindex(struct net_bridge *br, in br_mep_find_ifindex() argument
23 hlist_for_each_entry_rcu(mep, &br->mep_list, head, in br_mep_find_ifindex()
25 if (mep->create.ifindex == ifindex) in br_mep_find_ifindex()
36 hlist_for_each_entry_rcu(peer_mep, &mep->peer_mep_list, head, in br_peer_mep_find()
38 if (peer_mep->mepid == mepid) in br_peer_mep_find()
44 static struct net_bridge_port *br_mep_get_port(struct net_bridge *br, in br_mep_get_port() argument
49 list_for_each_entry(port, &br->port_list, list) in br_mep_get_port()
50 if (port->dev->ifindex == ifindex) in br_mep_get_port()
67 return 100 * 1000; in interval_to_us()
87 return 1; in interval_to_pdu()
110 case 1: in pdu_to_interval()
132 interval_us = interval_to_us(peer_mep->mep->cc_config.exp_interval); in ccm_rx_timer_start()
133 /* Function ccm_rx_dwork must be called with 1/4 in ccm_rx_timer_start()
137 queue_delayed_work(system_wq, &peer_mep->ccm_rx_dwork, in ccm_rx_timer_start()
145 br_info_notify(event, port->br, NULL, filter); in br_cfm_notify()
150 memset(&peer_mep->cc_status, 0, sizeof(peer_mep->cc_status)); in cc_peer_enable()
151 peer_mep->ccm_rx_count_miss = 0; in cc_peer_enable()
158 cancel_delayed_work_sync(&peer_mep->ccm_rx_dwork); in cc_peer_disable()
180 b_port = rcu_dereference(mep->b_port); in ccm_frame_build()
186 skb->dev = b_port->dev; in ccm_frame_build()
193 skb->protocol = htons(ETH_P_CFM); in ccm_frame_build()
194 skb->priority = CFM_FRAME_PRIO; in ccm_frame_build()
198 ether_addr_copy(eth_hdr->h_dest, tx_info->dmac.addr); in ccm_frame_build()
199 ether_addr_copy(eth_hdr->h_source, mep->config.unicast_mac.addr); in ccm_frame_build()
200 eth_hdr->h_proto = htons(ETH_P_CFM); in ccm_frame_build()
204 common_hdr->mdlevel_version = mep->config.mdlevel << 5; in ccm_frame_build()
205 common_hdr->opcode = BR_CFM_OPCODE_CCM; in ccm_frame_build()
206 common_hdr->flags = (mep->rdi << 7) | in ccm_frame_build()
207 interval_to_pdu(mep->cc_config.exp_interval); in ccm_frame_build()
208 common_hdr->tlv_offset = CFM_CCM_TLV_OFFSET; in ccm_frame_build()
212 if (tx_info->seq_no_update) { in ccm_frame_build()
213 *snumber = cpu_to_be32(mep->ccm_tx_snumber); in ccm_frame_build()
214 mep->ccm_tx_snumber += 1; in ccm_frame_build()
220 *mepid = cpu_to_be16((u16)mep->config.mepid); in ccm_frame_build()
223 memcpy(maid->data, mep->cc_config.exp_maid.data, sizeof(maid->data)); in ccm_frame_build()
235 /* Port status TLV. The value length is 1. Total of 4 bytes. */ in ccm_frame_build()
236 if (tx_info->port_tlv) { in ccm_frame_build()
239 (1 << 8) | /* Value length */ in ccm_frame_build()
240 (tx_info->port_tlv_value & 0xFF)); in ccm_frame_build()
243 /* Interface status TLV. The value length is 1. Total of 4 bytes. */ in ccm_frame_build()
244 if (tx_info->if_tlv) { in ccm_frame_build()
247 (1 << 8) | /* Value length */ in ccm_frame_build()
248 (tx_info->if_tlv_value & 0xFF)); in ccm_frame_build()
277 if (time_before_eq(mep->ccm_tx_end, jiffies)) { in ccm_tx_work_expired()
279 mep->cc_ccm_tx_info.period = 0; in ccm_tx_work_expired()
283 skb = ccm_frame_build(mep, &mep->cc_ccm_tx_info); in ccm_tx_work_expired()
287 interval_us = interval_to_us(mep->cc_config.exp_interval); in ccm_tx_work_expired()
288 queue_delayed_work(system_wq, &mep->ccm_tx_dwork, in ccm_tx_work_expired()
292 /* This function is called with 1/4 of the configured CC 'expected_interval'
305 if (peer_mep->ccm_rx_count_miss < 13) { in ccm_rx_work_expired()
307 peer_mep->ccm_rx_count_miss++; in ccm_rx_work_expired()
315 peer_mep->cc_status.ccm_defect = true; in ccm_rx_work_expired()
317 /* Change in CCM defect status - notify */ in ccm_rx_work_expired()
319 b_port = rcu_dereference(peer_mep->mep->b_port); in ccm_rx_work_expired()
339 /* TLV is present - get the status TLV */ in ccm_tlv_extract()
349 peer_mep->cc_status.tlv_seen = true; in ccm_tlv_extract()
350 peer_mep->cc_status.if_tlv_value = (h_s_tlv & 0xFF); in ccm_tlv_extract()
355 peer_mep->cc_status.tlv_seen = true; in ccm_tlv_extract()
356 peer_mep->cc_status.port_tlv_value = (h_s_tlv & 0xFF); in ccm_tlv_extract()
360 /* The Organization-Specific TLV is not handled */ in ccm_tlv_extract()
379 struct net_bridge *br; in br_cfm_frame_rx() local
385 if (port->state == BR_STATE_DISABLED) in br_cfm_frame_rx()
390 return 1; in br_cfm_frame_rx()
392 br = port->br; in br_cfm_frame_rx()
393 mep = br_mep_find_ifindex(br, port->dev->ifindex); in br_cfm_frame_rx()
395 /* No MEP on this port - must be forwarded */ in br_cfm_frame_rx()
398 mdlevel = hdr->mdlevel_version >> 5; in br_cfm_frame_rx()
399 if (mdlevel > mep->config.mdlevel) in br_cfm_frame_rx()
400 /* The level is above this MEP level - must be forwarded */ in br_cfm_frame_rx()
403 if ((hdr->mdlevel_version & 0x1F) != 0) { in br_cfm_frame_rx()
405 mep->status.version_unexp_seen = true; in br_cfm_frame_rx()
406 return 1; in br_cfm_frame_rx()
409 if (mdlevel < mep->config.mdlevel) { in br_cfm_frame_rx()
411 mep->status.rx_level_low_seen = true; in br_cfm_frame_rx()
412 return 1; in br_cfm_frame_rx()
415 if (hdr->opcode == BR_CFM_OPCODE_CCM) { in br_cfm_frame_rx()
422 return 1; in br_cfm_frame_rx()
423 if (memcmp(maid->data, mep->cc_config.exp_maid.data, in br_cfm_frame_rx()
424 sizeof(maid->data))) in br_cfm_frame_rx()
426 return 1; in br_cfm_frame_rx()
433 return 1; in br_cfm_frame_rx()
436 return 1; in br_cfm_frame_rx()
439 interval = hdr->flags & 0x07; in br_cfm_frame_rx()
440 if (mep->cc_config.exp_interval != pdu_to_interval(interval)) in br_cfm_frame_rx()
442 return 1; in br_cfm_frame_rx()
445 if (peer_mep->cc_status.ccm_defect) { in br_cfm_frame_rx()
446 peer_mep->cc_status.ccm_defect = false; in br_cfm_frame_rx()
448 /* Change in CCM defect status - notify */ in br_cfm_frame_rx()
455 peer_mep->cc_status.seen = true; in br_cfm_frame_rx()
456 peer_mep->ccm_rx_count_miss = 0; in br_cfm_frame_rx()
459 peer_mep->cc_status.rdi = (hdr->flags & 0x80) ? true : false; in br_cfm_frame_rx()
466 return 1; in br_cfm_frame_rx()
467 if (ntohl(*snumber) != (mep->ccm_rx_snumber + 1)) in br_cfm_frame_rx()
469 peer_mep->cc_status.seq_unexp_seen = true; in br_cfm_frame_rx()
471 mep->ccm_rx_snumber = ntohl(*snumber); in br_cfm_frame_rx()
481 max += 1; in br_cfm_frame_rx()
484 return 1; in br_cfm_frame_rx()
487 mep->status.opcode_unexp_seen = true; in br_cfm_frame_rx()
489 return 1; in br_cfm_frame_rx()
497 int br_cfm_mep_create(struct net_bridge *br, in br_cfm_mep_create() argument
507 if (create->domain == BR_CFM_VLAN) { in br_cfm_mep_create()
510 return -EINVAL; in br_cfm_mep_create()
512 if (create->domain != BR_CFM_PORT) { in br_cfm_mep_create()
515 return -EINVAL; in br_cfm_mep_create()
517 if (create->direction == BR_CFM_MEP_DIRECTION_UP) { in br_cfm_mep_create()
519 "Up-MEP not supported"); in br_cfm_mep_create()
520 return -EINVAL; in br_cfm_mep_create()
522 if (create->direction != BR_CFM_MEP_DIRECTION_DOWN) { in br_cfm_mep_create()
525 return -EINVAL; in br_cfm_mep_create()
527 p = br_mep_get_port(br, create->ifindex); in br_cfm_mep_create()
531 return -EINVAL; in br_cfm_mep_create()
533 mep = br_mep_find(br, instance); in br_cfm_mep_create()
537 return -EEXIST; in br_cfm_mep_create()
541 if (create->domain == BR_CFM_PORT) { in br_cfm_mep_create()
542 mep = br_mep_find_ifindex(br, create->ifindex); in br_cfm_mep_create()
546 return -EINVAL; in br_cfm_mep_create()
552 return -ENOMEM; in br_cfm_mep_create()
554 mep->create = *create; in br_cfm_mep_create()
555 mep->instance = instance; in br_cfm_mep_create()
556 rcu_assign_pointer(mep->b_port, p); in br_cfm_mep_create()
558 INIT_HLIST_HEAD(&mep->peer_mep_list); in br_cfm_mep_create()
559 INIT_DELAYED_WORK(&mep->ccm_tx_dwork, ccm_tx_work_expired); in br_cfm_mep_create()
561 if (hlist_empty(&br->mep_list)) in br_cfm_mep_create()
562 br_add_frame(br, &cfm_frame_type); in br_cfm_mep_create()
564 hlist_add_tail_rcu(&mep->head, &br->mep_list); in br_cfm_mep_create()
569 static void mep_delete_implementation(struct net_bridge *br, in mep_delete_implementation() argument
578 hlist_for_each_entry_safe(peer_mep, n_store, &mep->peer_mep_list, head) { in mep_delete_implementation()
579 cancel_delayed_work_sync(&peer_mep->ccm_rx_dwork); in mep_delete_implementation()
580 hlist_del_rcu(&peer_mep->head); in mep_delete_implementation()
584 cancel_delayed_work_sync(&mep->ccm_tx_dwork); in mep_delete_implementation()
586 RCU_INIT_POINTER(mep->b_port, NULL); in mep_delete_implementation()
587 hlist_del_rcu(&mep->head); in mep_delete_implementation()
590 if (hlist_empty(&br->mep_list)) in mep_delete_implementation()
591 br_del_frame(br, &cfm_frame_type); in mep_delete_implementation()
594 int br_cfm_mep_delete(struct net_bridge *br, in br_cfm_mep_delete() argument
602 mep = br_mep_find(br, instance); in br_cfm_mep_delete()
606 return -ENOENT; in br_cfm_mep_delete()
609 mep_delete_implementation(br, mep); in br_cfm_mep_delete()
614 int br_cfm_mep_config_set(struct net_bridge *br, in br_cfm_mep_config_set() argument
623 mep = br_mep_find(br, instance); in br_cfm_mep_config_set()
627 return -ENOENT; in br_cfm_mep_config_set()
630 mep->config = *config; in br_cfm_mep_config_set()
635 int br_cfm_cc_config_set(struct net_bridge *br, in br_cfm_cc_config_set() argument
645 mep = br_mep_find(br, instance); in br_cfm_cc_config_set()
649 return -ENOENT; in br_cfm_cc_config_set()
653 if (memcmp(config, &mep->cc_config, sizeof(*config)) == 0) in br_cfm_cc_config_set()
656 if (config->enable && !mep->cc_config.enable) in br_cfm_cc_config_set()
658 hlist_for_each_entry(peer_mep, &mep->peer_mep_list, head) in br_cfm_cc_config_set()
661 if (!config->enable && mep->cc_config.enable) in br_cfm_cc_config_set()
663 hlist_for_each_entry(peer_mep, &mep->peer_mep_list, head) in br_cfm_cc_config_set()
666 mep->cc_config = *config; in br_cfm_cc_config_set()
667 mep->ccm_rx_snumber = 0; in br_cfm_cc_config_set()
668 mep->ccm_tx_snumber = 1; in br_cfm_cc_config_set()
673 int br_cfm_cc_peer_mep_add(struct net_bridge *br, const u32 instance, in br_cfm_cc_peer_mep_add() argument
682 mep = br_mep_find(br, instance); in br_cfm_cc_peer_mep_add()
686 return -ENOENT; in br_cfm_cc_peer_mep_add()
692 "Peer MEP-ID already exists"); in br_cfm_cc_peer_mep_add()
693 return -EEXIST; in br_cfm_cc_peer_mep_add()
698 return -ENOMEM; in br_cfm_cc_peer_mep_add()
700 peer_mep->mepid = mepid; in br_cfm_cc_peer_mep_add()
701 peer_mep->mep = mep; in br_cfm_cc_peer_mep_add()
702 INIT_DELAYED_WORK(&peer_mep->ccm_rx_dwork, ccm_rx_work_expired); in br_cfm_cc_peer_mep_add()
704 if (mep->cc_config.enable) in br_cfm_cc_peer_mep_add()
707 hlist_add_tail_rcu(&peer_mep->head, &mep->peer_mep_list); in br_cfm_cc_peer_mep_add()
712 int br_cfm_cc_peer_mep_remove(struct net_bridge *br, const u32 instance, in br_cfm_cc_peer_mep_remove() argument
721 mep = br_mep_find(br, instance); in br_cfm_cc_peer_mep_remove()
725 return -ENOENT; in br_cfm_cc_peer_mep_remove()
731 "Peer MEP-ID does not exists"); in br_cfm_cc_peer_mep_remove()
732 return -ENOENT; in br_cfm_cc_peer_mep_remove()
737 hlist_del_rcu(&peer_mep->head); in br_cfm_cc_peer_mep_remove()
743 int br_cfm_cc_rdi_set(struct net_bridge *br, const u32 instance, in br_cfm_cc_rdi_set() argument
750 mep = br_mep_find(br, instance); in br_cfm_cc_rdi_set()
754 return -ENOENT; in br_cfm_cc_rdi_set()
757 mep->rdi = rdi; in br_cfm_cc_rdi_set()
762 int br_cfm_cc_ccm_tx(struct net_bridge *br, const u32 instance, in br_cfm_cc_ccm_tx() argument
770 mep = br_mep_find(br, instance); in br_cfm_cc_ccm_tx()
774 return -ENOENT; in br_cfm_cc_ccm_tx()
777 if (memcmp(tx_info, &mep->cc_ccm_tx_info, sizeof(*tx_info)) == 0) { in br_cfm_cc_ccm_tx()
779 if (mep->cc_ccm_tx_info.period == 0) in br_cfm_cc_ccm_tx()
780 /* Transmission is not enabled - just return */ in br_cfm_cc_ccm_tx()
784 mep->ccm_tx_end = jiffies + in br_cfm_cc_ccm_tx()
785 usecs_to_jiffies(tx_info->period * 1000000); in br_cfm_cc_ccm_tx()
789 if (tx_info->period == 0 && mep->cc_ccm_tx_info.period == 0) in br_cfm_cc_ccm_tx()
793 if (tx_info->period != 0 && mep->cc_ccm_tx_info.period != 0) { in br_cfm_cc_ccm_tx()
797 mep->ccm_tx_end = jiffies + in br_cfm_cc_ccm_tx()
798 usecs_to_jiffies(tx_info->period * 1000000); in br_cfm_cc_ccm_tx()
803 if (tx_info->period == 0 && mep->cc_ccm_tx_info.period != 0) { in br_cfm_cc_ccm_tx()
804 cancel_delayed_work_sync(&mep->ccm_tx_dwork); in br_cfm_cc_ccm_tx()
811 mep->ccm_tx_end = jiffies + usecs_to_jiffies(tx_info->period * 1000000); in br_cfm_cc_ccm_tx()
812 queue_delayed_work(system_wq, &mep->ccm_tx_dwork, 0); in br_cfm_cc_ccm_tx()
815 mep->cc_ccm_tx_info = *tx_info; in br_cfm_cc_ccm_tx()
820 int br_cfm_mep_count(struct net_bridge *br, u32 *count) in br_cfm_mep_count() argument
827 hlist_for_each_entry_rcu(mep, &br->mep_list, head) in br_cfm_mep_count()
828 *count += 1; in br_cfm_mep_count()
834 int br_cfm_peer_mep_count(struct net_bridge *br, u32 *count) in br_cfm_peer_mep_count() argument
842 hlist_for_each_entry_rcu(mep, &br->mep_list, head) in br_cfm_peer_mep_count()
843 hlist_for_each_entry_rcu(peer_mep, &mep->peer_mep_list, head) in br_cfm_peer_mep_count()
844 *count += 1; in br_cfm_peer_mep_count()
850 bool br_cfm_created(struct net_bridge *br) in br_cfm_created() argument
852 return !hlist_empty(&br->mep_list); in br_cfm_created()
857 void br_cfm_port_del(struct net_bridge *br, struct net_bridge_port *port) in br_cfm_port_del() argument
864 hlist_for_each_entry_safe(mep, n_store, &br->mep_list, head) in br_cfm_port_del()
865 if (mep->create.ifindex == port->dev->ifindex) in br_cfm_port_del()
866 mep_delete_implementation(br, mep); in br_cfm_port_del()