0001
0002
0003 #include <linux/cfm_bridge.h>
0004 #include <uapi/linux/cfm_bridge.h>
0005 #include "br_private_cfm.h"
0006
0007 static struct br_cfm_mep *br_mep_find(struct net_bridge *br, u32 instance)
0008 {
0009 struct br_cfm_mep *mep;
0010
0011 hlist_for_each_entry(mep, &br->mep_list, head)
0012 if (mep->instance == instance)
0013 return mep;
0014
0015 return NULL;
0016 }
0017
0018 static struct br_cfm_mep *br_mep_find_ifindex(struct net_bridge *br,
0019 u32 ifindex)
0020 {
0021 struct br_cfm_mep *mep;
0022
0023 hlist_for_each_entry_rcu(mep, &br->mep_list, head,
0024 lockdep_rtnl_is_held())
0025 if (mep->create.ifindex == ifindex)
0026 return mep;
0027
0028 return NULL;
0029 }
0030
0031 static struct br_cfm_peer_mep *br_peer_mep_find(struct br_cfm_mep *mep,
0032 u32 mepid)
0033 {
0034 struct br_cfm_peer_mep *peer_mep;
0035
0036 hlist_for_each_entry_rcu(peer_mep, &mep->peer_mep_list, head,
0037 lockdep_rtnl_is_held())
0038 if (peer_mep->mepid == mepid)
0039 return peer_mep;
0040
0041 return NULL;
0042 }
0043
0044 static struct net_bridge_port *br_mep_get_port(struct net_bridge *br,
0045 u32 ifindex)
0046 {
0047 struct net_bridge_port *port;
0048
0049 list_for_each_entry(port, &br->port_list, list)
0050 if (port->dev->ifindex == ifindex)
0051 return port;
0052
0053 return NULL;
0054 }
0055
0056
0057 static u32 interval_to_us(enum br_cfm_ccm_interval interval)
0058 {
0059 switch (interval) {
0060 case BR_CFM_CCM_INTERVAL_NONE:
0061 return 0;
0062 case BR_CFM_CCM_INTERVAL_3_3_MS:
0063 return 3300;
0064 case BR_CFM_CCM_INTERVAL_10_MS:
0065 return 10 * 1000;
0066 case BR_CFM_CCM_INTERVAL_100_MS:
0067 return 100 * 1000;
0068 case BR_CFM_CCM_INTERVAL_1_SEC:
0069 return 1000 * 1000;
0070 case BR_CFM_CCM_INTERVAL_10_SEC:
0071 return 10 * 1000 * 1000;
0072 case BR_CFM_CCM_INTERVAL_1_MIN:
0073 return 60 * 1000 * 1000;
0074 case BR_CFM_CCM_INTERVAL_10_MIN:
0075 return 10 * 60 * 1000 * 1000;
0076 }
0077 return 0;
0078 }
0079
0080
0081 static u32 interval_to_pdu(enum br_cfm_ccm_interval interval)
0082 {
0083 switch (interval) {
0084 case BR_CFM_CCM_INTERVAL_NONE:
0085 return 0;
0086 case BR_CFM_CCM_INTERVAL_3_3_MS:
0087 return 1;
0088 case BR_CFM_CCM_INTERVAL_10_MS:
0089 return 2;
0090 case BR_CFM_CCM_INTERVAL_100_MS:
0091 return 3;
0092 case BR_CFM_CCM_INTERVAL_1_SEC:
0093 return 4;
0094 case BR_CFM_CCM_INTERVAL_10_SEC:
0095 return 5;
0096 case BR_CFM_CCM_INTERVAL_1_MIN:
0097 return 6;
0098 case BR_CFM_CCM_INTERVAL_10_MIN:
0099 return 7;
0100 }
0101 return 0;
0102 }
0103
0104
0105 static u32 pdu_to_interval(u32 value)
0106 {
0107 switch (value) {
0108 case 0:
0109 return BR_CFM_CCM_INTERVAL_NONE;
0110 case 1:
0111 return BR_CFM_CCM_INTERVAL_3_3_MS;
0112 case 2:
0113 return BR_CFM_CCM_INTERVAL_10_MS;
0114 case 3:
0115 return BR_CFM_CCM_INTERVAL_100_MS;
0116 case 4:
0117 return BR_CFM_CCM_INTERVAL_1_SEC;
0118 case 5:
0119 return BR_CFM_CCM_INTERVAL_10_SEC;
0120 case 6:
0121 return BR_CFM_CCM_INTERVAL_1_MIN;
0122 case 7:
0123 return BR_CFM_CCM_INTERVAL_10_MIN;
0124 }
0125 return BR_CFM_CCM_INTERVAL_NONE;
0126 }
0127
0128 static void ccm_rx_timer_start(struct br_cfm_peer_mep *peer_mep)
0129 {
0130 u32 interval_us;
0131
0132 interval_us = interval_to_us(peer_mep->mep->cc_config.exp_interval);
0133
0134
0135
0136
0137 queue_delayed_work(system_wq, &peer_mep->ccm_rx_dwork,
0138 usecs_to_jiffies(interval_us / 4));
0139 }
0140
0141 static void br_cfm_notify(int event, const struct net_bridge_port *port)
0142 {
0143 u32 filter = RTEXT_FILTER_CFM_STATUS;
0144
0145 br_info_notify(event, port->br, NULL, filter);
0146 }
0147
0148 static void cc_peer_enable(struct br_cfm_peer_mep *peer_mep)
0149 {
0150 memset(&peer_mep->cc_status, 0, sizeof(peer_mep->cc_status));
0151 peer_mep->ccm_rx_count_miss = 0;
0152
0153 ccm_rx_timer_start(peer_mep);
0154 }
0155
0156 static void cc_peer_disable(struct br_cfm_peer_mep *peer_mep)
0157 {
0158 cancel_delayed_work_sync(&peer_mep->ccm_rx_dwork);
0159 }
0160
0161 static struct sk_buff *ccm_frame_build(struct br_cfm_mep *mep,
0162 const struct br_cfm_cc_ccm_tx_info *const tx_info)
0163
0164 {
0165 struct br_cfm_common_hdr *common_hdr;
0166 struct net_bridge_port *b_port;
0167 struct br_cfm_maid *maid;
0168 u8 *itu_reserved, *e_tlv;
0169 struct ethhdr *eth_hdr;
0170 struct sk_buff *skb;
0171 __be32 *status_tlv;
0172 __be32 *snumber;
0173 __be16 *mepid;
0174
0175 skb = dev_alloc_skb(CFM_CCM_MAX_FRAME_LENGTH);
0176 if (!skb)
0177 return NULL;
0178
0179 rcu_read_lock();
0180 b_port = rcu_dereference(mep->b_port);
0181 if (!b_port) {
0182 kfree_skb(skb);
0183 rcu_read_unlock();
0184 return NULL;
0185 }
0186 skb->dev = b_port->dev;
0187 rcu_read_unlock();
0188
0189
0190
0191
0192
0193 skb->protocol = htons(ETH_P_CFM);
0194 skb->priority = CFM_FRAME_PRIO;
0195
0196
0197 eth_hdr = skb_put(skb, sizeof(*eth_hdr));
0198 ether_addr_copy(eth_hdr->h_dest, tx_info->dmac.addr);
0199 ether_addr_copy(eth_hdr->h_source, mep->config.unicast_mac.addr);
0200 eth_hdr->h_proto = htons(ETH_P_CFM);
0201
0202
0203 common_hdr = skb_put(skb, sizeof(*common_hdr));
0204 common_hdr->mdlevel_version = mep->config.mdlevel << 5;
0205 common_hdr->opcode = BR_CFM_OPCODE_CCM;
0206 common_hdr->flags = (mep->rdi << 7) |
0207 interval_to_pdu(mep->cc_config.exp_interval);
0208 common_hdr->tlv_offset = CFM_CCM_TLV_OFFSET;
0209
0210
0211 snumber = skb_put(skb, sizeof(*snumber));
0212 if (tx_info->seq_no_update) {
0213 *snumber = cpu_to_be32(mep->ccm_tx_snumber);
0214 mep->ccm_tx_snumber += 1;
0215 } else {
0216 *snumber = 0;
0217 }
0218
0219 mepid = skb_put(skb, sizeof(*mepid));
0220 *mepid = cpu_to_be16((u16)mep->config.mepid);
0221
0222 maid = skb_put(skb, sizeof(*maid));
0223 memcpy(maid->data, mep->cc_config.exp_maid.data, sizeof(maid->data));
0224
0225
0226 itu_reserved = skb_put(skb, CFM_CCM_ITU_RESERVED_SIZE);
0227 memset(itu_reserved, 0, CFM_CCM_ITU_RESERVED_SIZE);
0228
0229
0230
0231
0232
0233
0234
0235
0236 if (tx_info->port_tlv) {
0237 status_tlv = skb_put(skb, sizeof(*status_tlv));
0238 *status_tlv = cpu_to_be32((CFM_PORT_STATUS_TLV_TYPE << 24) |
0239 (1 << 8) |
0240 (tx_info->port_tlv_value & 0xFF));
0241 }
0242
0243
0244 if (tx_info->if_tlv) {
0245 status_tlv = skb_put(skb, sizeof(*status_tlv));
0246 *status_tlv = cpu_to_be32((CFM_IF_STATUS_TLV_TYPE << 24) |
0247 (1 << 8) |
0248 (tx_info->if_tlv_value & 0xFF));
0249 }
0250
0251
0252 e_tlv = skb_put(skb, sizeof(*e_tlv));
0253 *e_tlv = CFM_ENDE_TLV_TYPE;
0254
0255 return skb;
0256 }
0257
0258 static void ccm_frame_tx(struct sk_buff *skb)
0259 {
0260 skb_reset_network_header(skb);
0261 dev_queue_xmit(skb);
0262 }
0263
0264
0265
0266
0267 static void ccm_tx_work_expired(struct work_struct *work)
0268 {
0269 struct delayed_work *del_work;
0270 struct br_cfm_mep *mep;
0271 struct sk_buff *skb;
0272 u32 interval_us;
0273
0274 del_work = to_delayed_work(work);
0275 mep = container_of(del_work, struct br_cfm_mep, ccm_tx_dwork);
0276
0277 if (time_before_eq(mep->ccm_tx_end, jiffies)) {
0278
0279 mep->cc_ccm_tx_info.period = 0;
0280 return;
0281 }
0282
0283 skb = ccm_frame_build(mep, &mep->cc_ccm_tx_info);
0284 if (skb)
0285 ccm_frame_tx(skb);
0286
0287 interval_us = interval_to_us(mep->cc_config.exp_interval);
0288 queue_delayed_work(system_wq, &mep->ccm_tx_dwork,
0289 usecs_to_jiffies(interval_us));
0290 }
0291
0292
0293
0294
0295 static void ccm_rx_work_expired(struct work_struct *work)
0296 {
0297 struct br_cfm_peer_mep *peer_mep;
0298 struct net_bridge_port *b_port;
0299 struct delayed_work *del_work;
0300
0301 del_work = to_delayed_work(work);
0302 peer_mep = container_of(del_work, struct br_cfm_peer_mep, ccm_rx_dwork);
0303
0304
0305 if (peer_mep->ccm_rx_count_miss < 13) {
0306
0307 peer_mep->ccm_rx_count_miss++;
0308
0309
0310 ccm_rx_timer_start(peer_mep);
0311 } else {
0312
0313
0314
0315 peer_mep->cc_status.ccm_defect = true;
0316
0317
0318 rcu_read_lock();
0319 b_port = rcu_dereference(peer_mep->mep->b_port);
0320 if (b_port)
0321 br_cfm_notify(RTM_NEWLINK, b_port);
0322 rcu_read_unlock();
0323 }
0324 }
0325
0326 static u32 ccm_tlv_extract(struct sk_buff *skb, u32 index,
0327 struct br_cfm_peer_mep *peer_mep)
0328 {
0329 __be32 *s_tlv;
0330 __be32 _s_tlv;
0331 u32 h_s_tlv;
0332 u8 *e_tlv;
0333 u8 _e_tlv;
0334
0335 e_tlv = skb_header_pointer(skb, index, sizeof(_e_tlv), &_e_tlv);
0336 if (!e_tlv)
0337 return 0;
0338
0339
0340 s_tlv = skb_header_pointer(skb,
0341 index,
0342 sizeof(_s_tlv), &_s_tlv);
0343 if (!s_tlv)
0344 return 0;
0345
0346 h_s_tlv = ntohl(*s_tlv);
0347 if ((h_s_tlv >> 24) == CFM_IF_STATUS_TLV_TYPE) {
0348
0349 peer_mep->cc_status.tlv_seen = true;
0350 peer_mep->cc_status.if_tlv_value = (h_s_tlv & 0xFF);
0351 }
0352
0353 if ((h_s_tlv >> 24) == CFM_PORT_STATUS_TLV_TYPE) {
0354
0355 peer_mep->cc_status.tlv_seen = true;
0356 peer_mep->cc_status.port_tlv_value = (h_s_tlv & 0xFF);
0357 }
0358
0359
0360
0361
0362
0363
0364
0365
0366 return ((h_s_tlv >> 8) & 0xFFFF) + 3;
0367 }
0368
0369
0370 static int br_cfm_frame_rx(struct net_bridge_port *port, struct sk_buff *skb)
0371 {
0372 u32 mdlevel, interval, size, index, max;
0373 const struct br_cfm_common_hdr *hdr;
0374 struct br_cfm_peer_mep *peer_mep;
0375 const struct br_cfm_maid *maid;
0376 struct br_cfm_common_hdr _hdr;
0377 struct br_cfm_maid _maid;
0378 struct br_cfm_mep *mep;
0379 struct net_bridge *br;
0380 __be32 *snumber;
0381 __be32 _snumber;
0382 __be16 *mepid;
0383 __be16 _mepid;
0384
0385 if (port->state == BR_STATE_DISABLED)
0386 return 0;
0387
0388 hdr = skb_header_pointer(skb, 0, sizeof(_hdr), &_hdr);
0389 if (!hdr)
0390 return 1;
0391
0392 br = port->br;
0393 mep = br_mep_find_ifindex(br, port->dev->ifindex);
0394 if (unlikely(!mep))
0395
0396 return 0;
0397
0398 mdlevel = hdr->mdlevel_version >> 5;
0399 if (mdlevel > mep->config.mdlevel)
0400
0401 return 0;
0402
0403 if ((hdr->mdlevel_version & 0x1F) != 0) {
0404
0405 mep->status.version_unexp_seen = true;
0406 return 1;
0407 }
0408
0409 if (mdlevel < mep->config.mdlevel) {
0410
0411 mep->status.rx_level_low_seen = true;
0412 return 1;
0413 }
0414
0415 if (hdr->opcode == BR_CFM_OPCODE_CCM) {
0416
0417
0418 maid = skb_header_pointer(skb,
0419 CFM_CCM_PDU_MAID_OFFSET,
0420 sizeof(_maid), &_maid);
0421 if (!maid)
0422 return 1;
0423 if (memcmp(maid->data, mep->cc_config.exp_maid.data,
0424 sizeof(maid->data)))
0425
0426 return 1;
0427
0428
0429 mepid = skb_header_pointer(skb,
0430 CFM_CCM_PDU_MEPID_OFFSET,
0431 sizeof(_mepid), &_mepid);
0432 if (!mepid)
0433 return 1;
0434 peer_mep = br_peer_mep_find(mep, (u32)ntohs(*mepid));
0435 if (!peer_mep)
0436 return 1;
0437
0438
0439 interval = hdr->flags & 0x07;
0440 if (mep->cc_config.exp_interval != pdu_to_interval(interval))
0441
0442 return 1;
0443
0444
0445 if (peer_mep->cc_status.ccm_defect) {
0446 peer_mep->cc_status.ccm_defect = false;
0447
0448
0449 br_cfm_notify(RTM_NEWLINK, port);
0450
0451
0452 ccm_rx_timer_start(peer_mep);
0453 }
0454
0455 peer_mep->cc_status.seen = true;
0456 peer_mep->ccm_rx_count_miss = 0;
0457
0458
0459 peer_mep->cc_status.rdi = (hdr->flags & 0x80) ? true : false;
0460
0461
0462 snumber = skb_header_pointer(skb,
0463 CFM_CCM_PDU_SEQNR_OFFSET,
0464 sizeof(_snumber), &_snumber);
0465 if (!snumber)
0466 return 1;
0467 if (ntohl(*snumber) != (mep->ccm_rx_snumber + 1))
0468
0469 peer_mep->cc_status.seq_unexp_seen = true;
0470
0471 mep->ccm_rx_snumber = ntohl(*snumber);
0472
0473
0474
0475
0476 index = CFM_CCM_PDU_TLV_OFFSET;
0477 max = 0;
0478 do {
0479 size = ccm_tlv_extract(skb, index, peer_mep);
0480 index += size;
0481 max += 1;
0482 } while (size != 0 && max < 4);
0483
0484 return 1;
0485 }
0486
0487 mep->status.opcode_unexp_seen = true;
0488
0489 return 1;
0490 }
0491
0492 static struct br_frame_type cfm_frame_type __read_mostly = {
0493 .type = cpu_to_be16(ETH_P_CFM),
0494 .frame_handler = br_cfm_frame_rx,
0495 };
0496
0497 int br_cfm_mep_create(struct net_bridge *br,
0498 const u32 instance,
0499 struct br_cfm_mep_create *const create,
0500 struct netlink_ext_ack *extack)
0501 {
0502 struct net_bridge_port *p;
0503 struct br_cfm_mep *mep;
0504
0505 ASSERT_RTNL();
0506
0507 if (create->domain == BR_CFM_VLAN) {
0508 NL_SET_ERR_MSG_MOD(extack,
0509 "VLAN domain not supported");
0510 return -EINVAL;
0511 }
0512 if (create->domain != BR_CFM_PORT) {
0513 NL_SET_ERR_MSG_MOD(extack,
0514 "Invalid domain value");
0515 return -EINVAL;
0516 }
0517 if (create->direction == BR_CFM_MEP_DIRECTION_UP) {
0518 NL_SET_ERR_MSG_MOD(extack,
0519 "Up-MEP not supported");
0520 return -EINVAL;
0521 }
0522 if (create->direction != BR_CFM_MEP_DIRECTION_DOWN) {
0523 NL_SET_ERR_MSG_MOD(extack,
0524 "Invalid direction value");
0525 return -EINVAL;
0526 }
0527 p = br_mep_get_port(br, create->ifindex);
0528 if (!p) {
0529 NL_SET_ERR_MSG_MOD(extack,
0530 "Port is not related to bridge");
0531 return -EINVAL;
0532 }
0533 mep = br_mep_find(br, instance);
0534 if (mep) {
0535 NL_SET_ERR_MSG_MOD(extack,
0536 "MEP instance already exists");
0537 return -EEXIST;
0538 }
0539
0540
0541 if (create->domain == BR_CFM_PORT) {
0542 mep = br_mep_find_ifindex(br, create->ifindex);
0543 if (mep) {
0544 NL_SET_ERR_MSG_MOD(extack,
0545 "Only one Port MEP on a port allowed");
0546 return -EINVAL;
0547 }
0548 }
0549
0550 mep = kzalloc(sizeof(*mep), GFP_KERNEL);
0551 if (!mep)
0552 return -ENOMEM;
0553
0554 mep->create = *create;
0555 mep->instance = instance;
0556 rcu_assign_pointer(mep->b_port, p);
0557
0558 INIT_HLIST_HEAD(&mep->peer_mep_list);
0559 INIT_DELAYED_WORK(&mep->ccm_tx_dwork, ccm_tx_work_expired);
0560
0561 if (hlist_empty(&br->mep_list))
0562 br_add_frame(br, &cfm_frame_type);
0563
0564 hlist_add_tail_rcu(&mep->head, &br->mep_list);
0565
0566 return 0;
0567 }
0568
0569 static void mep_delete_implementation(struct net_bridge *br,
0570 struct br_cfm_mep *mep)
0571 {
0572 struct br_cfm_peer_mep *peer_mep;
0573 struct hlist_node *n_store;
0574
0575 ASSERT_RTNL();
0576
0577
0578 hlist_for_each_entry_safe(peer_mep, n_store, &mep->peer_mep_list, head) {
0579 cancel_delayed_work_sync(&peer_mep->ccm_rx_dwork);
0580 hlist_del_rcu(&peer_mep->head);
0581 kfree_rcu(peer_mep, rcu);
0582 }
0583
0584 cancel_delayed_work_sync(&mep->ccm_tx_dwork);
0585
0586 RCU_INIT_POINTER(mep->b_port, NULL);
0587 hlist_del_rcu(&mep->head);
0588 kfree_rcu(mep, rcu);
0589
0590 if (hlist_empty(&br->mep_list))
0591 br_del_frame(br, &cfm_frame_type);
0592 }
0593
0594 int br_cfm_mep_delete(struct net_bridge *br,
0595 const u32 instance,
0596 struct netlink_ext_ack *extack)
0597 {
0598 struct br_cfm_mep *mep;
0599
0600 ASSERT_RTNL();
0601
0602 mep = br_mep_find(br, instance);
0603 if (!mep) {
0604 NL_SET_ERR_MSG_MOD(extack,
0605 "MEP instance does not exists");
0606 return -ENOENT;
0607 }
0608
0609 mep_delete_implementation(br, mep);
0610
0611 return 0;
0612 }
0613
0614 int br_cfm_mep_config_set(struct net_bridge *br,
0615 const u32 instance,
0616 const struct br_cfm_mep_config *const config,
0617 struct netlink_ext_ack *extack)
0618 {
0619 struct br_cfm_mep *mep;
0620
0621 ASSERT_RTNL();
0622
0623 mep = br_mep_find(br, instance);
0624 if (!mep) {
0625 NL_SET_ERR_MSG_MOD(extack,
0626 "MEP instance does not exists");
0627 return -ENOENT;
0628 }
0629
0630 mep->config = *config;
0631
0632 return 0;
0633 }
0634
0635 int br_cfm_cc_config_set(struct net_bridge *br,
0636 const u32 instance,
0637 const struct br_cfm_cc_config *const config,
0638 struct netlink_ext_ack *extack)
0639 {
0640 struct br_cfm_peer_mep *peer_mep;
0641 struct br_cfm_mep *mep;
0642
0643 ASSERT_RTNL();
0644
0645 mep = br_mep_find(br, instance);
0646 if (!mep) {
0647 NL_SET_ERR_MSG_MOD(extack,
0648 "MEP instance does not exists");
0649 return -ENOENT;
0650 }
0651
0652
0653 if (memcmp(config, &mep->cc_config, sizeof(*config)) == 0)
0654 return 0;
0655
0656 if (config->enable && !mep->cc_config.enable)
0657
0658 hlist_for_each_entry(peer_mep, &mep->peer_mep_list, head)
0659 cc_peer_enable(peer_mep);
0660
0661 if (!config->enable && mep->cc_config.enable)
0662
0663 hlist_for_each_entry(peer_mep, &mep->peer_mep_list, head)
0664 cc_peer_disable(peer_mep);
0665
0666 mep->cc_config = *config;
0667 mep->ccm_rx_snumber = 0;
0668 mep->ccm_tx_snumber = 1;
0669
0670 return 0;
0671 }
0672
0673 int br_cfm_cc_peer_mep_add(struct net_bridge *br, const u32 instance,
0674 u32 mepid,
0675 struct netlink_ext_ack *extack)
0676 {
0677 struct br_cfm_peer_mep *peer_mep;
0678 struct br_cfm_mep *mep;
0679
0680 ASSERT_RTNL();
0681
0682 mep = br_mep_find(br, instance);
0683 if (!mep) {
0684 NL_SET_ERR_MSG_MOD(extack,
0685 "MEP instance does not exists");
0686 return -ENOENT;
0687 }
0688
0689 peer_mep = br_peer_mep_find(mep, mepid);
0690 if (peer_mep) {
0691 NL_SET_ERR_MSG_MOD(extack,
0692 "Peer MEP-ID already exists");
0693 return -EEXIST;
0694 }
0695
0696 peer_mep = kzalloc(sizeof(*peer_mep), GFP_KERNEL);
0697 if (!peer_mep)
0698 return -ENOMEM;
0699
0700 peer_mep->mepid = mepid;
0701 peer_mep->mep = mep;
0702 INIT_DELAYED_WORK(&peer_mep->ccm_rx_dwork, ccm_rx_work_expired);
0703
0704 if (mep->cc_config.enable)
0705 cc_peer_enable(peer_mep);
0706
0707 hlist_add_tail_rcu(&peer_mep->head, &mep->peer_mep_list);
0708
0709 return 0;
0710 }
0711
0712 int br_cfm_cc_peer_mep_remove(struct net_bridge *br, const u32 instance,
0713 u32 mepid,
0714 struct netlink_ext_ack *extack)
0715 {
0716 struct br_cfm_peer_mep *peer_mep;
0717 struct br_cfm_mep *mep;
0718
0719 ASSERT_RTNL();
0720
0721 mep = br_mep_find(br, instance);
0722 if (!mep) {
0723 NL_SET_ERR_MSG_MOD(extack,
0724 "MEP instance does not exists");
0725 return -ENOENT;
0726 }
0727
0728 peer_mep = br_peer_mep_find(mep, mepid);
0729 if (!peer_mep) {
0730 NL_SET_ERR_MSG_MOD(extack,
0731 "Peer MEP-ID does not exists");
0732 return -ENOENT;
0733 }
0734
0735 cc_peer_disable(peer_mep);
0736
0737 hlist_del_rcu(&peer_mep->head);
0738 kfree_rcu(peer_mep, rcu);
0739
0740 return 0;
0741 }
0742
0743 int br_cfm_cc_rdi_set(struct net_bridge *br, const u32 instance,
0744 const bool rdi, struct netlink_ext_ack *extack)
0745 {
0746 struct br_cfm_mep *mep;
0747
0748 ASSERT_RTNL();
0749
0750 mep = br_mep_find(br, instance);
0751 if (!mep) {
0752 NL_SET_ERR_MSG_MOD(extack,
0753 "MEP instance does not exists");
0754 return -ENOENT;
0755 }
0756
0757 mep->rdi = rdi;
0758
0759 return 0;
0760 }
0761
0762 int br_cfm_cc_ccm_tx(struct net_bridge *br, const u32 instance,
0763 const struct br_cfm_cc_ccm_tx_info *const tx_info,
0764 struct netlink_ext_ack *extack)
0765 {
0766 struct br_cfm_mep *mep;
0767
0768 ASSERT_RTNL();
0769
0770 mep = br_mep_find(br, instance);
0771 if (!mep) {
0772 NL_SET_ERR_MSG_MOD(extack,
0773 "MEP instance does not exists");
0774 return -ENOENT;
0775 }
0776
0777 if (memcmp(tx_info, &mep->cc_ccm_tx_info, sizeof(*tx_info)) == 0) {
0778
0779 if (mep->cc_ccm_tx_info.period == 0)
0780
0781 return 0;
0782
0783
0784 mep->ccm_tx_end = jiffies +
0785 usecs_to_jiffies(tx_info->period * 1000000);
0786 return 0;
0787 }
0788
0789 if (tx_info->period == 0 && mep->cc_ccm_tx_info.period == 0)
0790
0791 goto save;
0792
0793 if (tx_info->period != 0 && mep->cc_ccm_tx_info.period != 0) {
0794
0795
0796
0797 mep->ccm_tx_end = jiffies +
0798 usecs_to_jiffies(tx_info->period * 1000000);
0799
0800 goto save;
0801 }
0802
0803 if (tx_info->period == 0 && mep->cc_ccm_tx_info.period != 0) {
0804 cancel_delayed_work_sync(&mep->ccm_tx_dwork);
0805 goto save;
0806 }
0807
0808
0809
0810
0811 mep->ccm_tx_end = jiffies + usecs_to_jiffies(tx_info->period * 1000000);
0812 queue_delayed_work(system_wq, &mep->ccm_tx_dwork, 0);
0813
0814 save:
0815 mep->cc_ccm_tx_info = *tx_info;
0816
0817 return 0;
0818 }
0819
0820 int br_cfm_mep_count(struct net_bridge *br, u32 *count)
0821 {
0822 struct br_cfm_mep *mep;
0823
0824 *count = 0;
0825
0826 rcu_read_lock();
0827 hlist_for_each_entry_rcu(mep, &br->mep_list, head)
0828 *count += 1;
0829 rcu_read_unlock();
0830
0831 return 0;
0832 }
0833
0834 int br_cfm_peer_mep_count(struct net_bridge *br, u32 *count)
0835 {
0836 struct br_cfm_peer_mep *peer_mep;
0837 struct br_cfm_mep *mep;
0838
0839 *count = 0;
0840
0841 rcu_read_lock();
0842 hlist_for_each_entry_rcu(mep, &br->mep_list, head)
0843 hlist_for_each_entry_rcu(peer_mep, &mep->peer_mep_list, head)
0844 *count += 1;
0845 rcu_read_unlock();
0846
0847 return 0;
0848 }
0849
0850 bool br_cfm_created(struct net_bridge *br)
0851 {
0852 return !hlist_empty(&br->mep_list);
0853 }
0854
0855
0856
0857 void br_cfm_port_del(struct net_bridge *br, struct net_bridge_port *port)
0858 {
0859 struct hlist_node *n_store;
0860 struct br_cfm_mep *mep;
0861
0862 ASSERT_RTNL();
0863
0864 hlist_for_each_entry_safe(mep, n_store, &br->mep_list, head)
0865 if (mep->create.ifindex == port->dev->ifindex)
0866 mep_delete_implementation(br, mep);
0867 }