Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bridge: cfm: Netlink SET configuration Interface.

This is the implementation of CFM netlink configuration
set information interface.

Add new nested netlink attributes. These attributes are used by the
user space to create/delete/configure CFM instances.

SETLINK:
IFLA_BRIDGE_CFM:
Indicate that the following attributes are CFM.

IFLA_BRIDGE_CFM_MEP_CREATE:
This indicate that a MEP instance must be created.
IFLA_BRIDGE_CFM_MEP_DELETE:
This indicate that a MEP instance must be deleted.
IFLA_BRIDGE_CFM_MEP_CONFIG:
This indicate that a MEP instance must be configured.
IFLA_BRIDGE_CFM_CC_CONFIG:
This indicate that a MEP instance Continuity Check (CC)
functionality must be configured.
IFLA_BRIDGE_CFM_CC_PEER_MEP_ADD:
This indicate that a CC Peer MEP must be added.
IFLA_BRIDGE_CFM_CC_PEER_MEP_REMOVE:
This indicate that a CC Peer MEP must be removed.
IFLA_BRIDGE_CFM_CC_CCM_TX:
This indicate that the CC transmitted CCM PDU must be configured.
IFLA_BRIDGE_CFM_CC_RDI:
This indicate that the CC transmitted CCM PDU RDI must be
configured.

CFM nested attribute has the following attributes in next level.

SETLINK RTEXT_FILTER_CFM_CONFIG:
IFLA_BRIDGE_CFM_MEP_CREATE_INSTANCE:
The created MEP instance number.
The type is u32.
IFLA_BRIDGE_CFM_MEP_CREATE_DOMAIN:
The created MEP domain.
The type is u32 (br_cfm_domain).
It must be BR_CFM_PORT.
This means that CFM frames are transmitted and received
directly on the port - untagged. Not in a VLAN.
IFLA_BRIDGE_CFM_MEP_CREATE_DIRECTION:
The created MEP direction.
The type is u32 (br_cfm_mep_direction).
It must be BR_CFM_MEP_DIRECTION_DOWN.
This means that CFM frames are transmitted and received on
the port. Not in the bridge.
IFLA_BRIDGE_CFM_MEP_CREATE_IFINDEX:
The created MEP residence port ifindex.
The type is u32 (ifindex).

IFLA_BRIDGE_CFM_MEP_DELETE_INSTANCE:
The deleted MEP instance number.
The type is u32.

IFLA_BRIDGE_CFM_MEP_CONFIG_INSTANCE:
The configured MEP instance number.
The type is u32.
IFLA_BRIDGE_CFM_MEP_CONFIG_UNICAST_MAC:
The configured MEP unicast MAC address.
The type is 6*u8 (array).
This is used as SMAC in all transmitted CFM frames.
IFLA_BRIDGE_CFM_MEP_CONFIG_MDLEVEL:
The configured MEP unicast MD level.
The type is u32.
It must be in the range 1-7.
No CFM frames are passing through this MEP on lower levels.
IFLA_BRIDGE_CFM_MEP_CONFIG_MEPID:
The configured MEP ID.
The type is u32.
It must be in the range 0-0x1FFF.
This MEP ID is inserted in any transmitted CCM frame.

IFLA_BRIDGE_CFM_CC_CONFIG_INSTANCE:
The configured MEP instance number.
The type is u32.
IFLA_BRIDGE_CFM_CC_CONFIG_ENABLE:
The Continuity Check (CC) functionality is enabled or disabled.
The type is u32 (bool).
IFLA_BRIDGE_CFM_CC_CONFIG_EXP_INTERVAL:
The CC expected receive interval of CCM frames.
The type is u32 (br_cfm_ccm_interval).
This is also the transmission interval of CCM frames when enabled.
IFLA_BRIDGE_CFM_CC_CONFIG_EXP_MAID:
The CC expected receive MAID in CCM frames.
The type is CFM_MAID_LENGTH*u8.
This is MAID is also inserted in transmitted CCM frames.

IFLA_BRIDGE_CFM_CC_PEER_MEP_INSTANCE:
The configured MEP instance number.
The type is u32.
IFLA_BRIDGE_CFM_CC_PEER_MEPID:
The CC Peer MEP ID added.
The type is u32.
When a Peer MEP ID is added and CC is enabled it is expected to
receive CCM frames from that Peer MEP.

IFLA_BRIDGE_CFM_CC_RDI_INSTANCE:
The configured MEP instance number.
The type is u32.
IFLA_BRIDGE_CFM_CC_RDI_RDI:
The RDI that is inserted in transmitted CCM PDU.
The type is u32 (bool).

IFLA_BRIDGE_CFM_CC_CCM_TX_INSTANCE:
The configured MEP instance number.
The type is u32.
IFLA_BRIDGE_CFM_CC_CCM_TX_DMAC:
The transmitted CCM frame destination MAC address.
The type is 6*u8 (array).
This is used as DMAC in all transmitted CFM frames.
IFLA_BRIDGE_CFM_CC_CCM_TX_SEQ_NO_UPDATE:
The transmitted CCM frame update (increment) of sequence
number is enabled or disabled.
The type is u32 (bool).
IFLA_BRIDGE_CFM_CC_CCM_TX_PERIOD:
The period of time where CCM frame are transmitted.
The type is u32.
The time is given in seconds. SETLINK IFLA_BRIDGE_CFM_CC_CCM_TX
must be done before timeout to keep transmission alive.
When period is zero any ongoing CCM frame transmission
will be stopped.
IFLA_BRIDGE_CFM_CC_CCM_TX_IF_TLV:
The transmitted CCM frame update with Interface Status TLV
is enabled or disabled.
The type is u32 (bool).
IFLA_BRIDGE_CFM_CC_CCM_TX_IF_TLV_VALUE:
The transmitted Interface Status TLV value field.
The type is u8.
IFLA_BRIDGE_CFM_CC_CCM_TX_PORT_TLV:
The transmitted CCM frame update with Port Status TLV is enabled
or disabled.
The type is u32 (bool).
IFLA_BRIDGE_CFM_CC_CCM_TX_PORT_TLV_VALUE:
The transmitted Port Status TLV value field.
The type is u8.

Signed-off-by: Henrik Bjoernlund <henrik.bjoernlund@microchip.com>
Reviewed-by: Horatiu Vultur <horatiu.vultur@microchip.com>
Acked-by: Nikolay Aleksandrov <nikolay@nvidia.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Henrik Bjoernlund and committed by
Jakub Kicinski
2be665c3 dc32cbb3

+571 -2
+90
include/uapi/linux/if_bridge.h
··· 121 121 IFLA_BRIDGE_VLAN_INFO, 122 122 IFLA_BRIDGE_VLAN_TUNNEL_INFO, 123 123 IFLA_BRIDGE_MRP, 124 + IFLA_BRIDGE_CFM, 124 125 __IFLA_BRIDGE_MAX, 125 126 }; 126 127 #define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1) ··· 328 327 __u32 period; 329 328 __u16 in_id; 330 329 }; 330 + 331 + enum { 332 + IFLA_BRIDGE_CFM_UNSPEC, 333 + IFLA_BRIDGE_CFM_MEP_CREATE, 334 + IFLA_BRIDGE_CFM_MEP_DELETE, 335 + IFLA_BRIDGE_CFM_MEP_CONFIG, 336 + IFLA_BRIDGE_CFM_CC_CONFIG, 337 + IFLA_BRIDGE_CFM_CC_PEER_MEP_ADD, 338 + IFLA_BRIDGE_CFM_CC_PEER_MEP_REMOVE, 339 + IFLA_BRIDGE_CFM_CC_RDI, 340 + IFLA_BRIDGE_CFM_CC_CCM_TX, 341 + __IFLA_BRIDGE_CFM_MAX, 342 + }; 343 + 344 + #define IFLA_BRIDGE_CFM_MAX (__IFLA_BRIDGE_CFM_MAX - 1) 345 + 346 + enum { 347 + IFLA_BRIDGE_CFM_MEP_CREATE_UNSPEC, 348 + IFLA_BRIDGE_CFM_MEP_CREATE_INSTANCE, 349 + IFLA_BRIDGE_CFM_MEP_CREATE_DOMAIN, 350 + IFLA_BRIDGE_CFM_MEP_CREATE_DIRECTION, 351 + IFLA_BRIDGE_CFM_MEP_CREATE_IFINDEX, 352 + __IFLA_BRIDGE_CFM_MEP_CREATE_MAX, 353 + }; 354 + 355 + #define IFLA_BRIDGE_CFM_MEP_CREATE_MAX (__IFLA_BRIDGE_CFM_MEP_CREATE_MAX - 1) 356 + 357 + enum { 358 + IFLA_BRIDGE_CFM_MEP_DELETE_UNSPEC, 359 + IFLA_BRIDGE_CFM_MEP_DELETE_INSTANCE, 360 + __IFLA_BRIDGE_CFM_MEP_DELETE_MAX, 361 + }; 362 + 363 + #define IFLA_BRIDGE_CFM_MEP_DELETE_MAX (__IFLA_BRIDGE_CFM_MEP_DELETE_MAX - 1) 364 + 365 + enum { 366 + IFLA_BRIDGE_CFM_MEP_CONFIG_UNSPEC, 367 + IFLA_BRIDGE_CFM_MEP_CONFIG_INSTANCE, 368 + IFLA_BRIDGE_CFM_MEP_CONFIG_UNICAST_MAC, 369 + IFLA_BRIDGE_CFM_MEP_CONFIG_MDLEVEL, 370 + IFLA_BRIDGE_CFM_MEP_CONFIG_MEPID, 371 + __IFLA_BRIDGE_CFM_MEP_CONFIG_MAX, 372 + }; 373 + 374 + #define IFLA_BRIDGE_CFM_MEP_CONFIG_MAX (__IFLA_BRIDGE_CFM_MEP_CONFIG_MAX - 1) 375 + 376 + enum { 377 + IFLA_BRIDGE_CFM_CC_CONFIG_UNSPEC, 378 + IFLA_BRIDGE_CFM_CC_CONFIG_INSTANCE, 379 + IFLA_BRIDGE_CFM_CC_CONFIG_ENABLE, 380 + IFLA_BRIDGE_CFM_CC_CONFIG_EXP_INTERVAL, 381 + IFLA_BRIDGE_CFM_CC_CONFIG_EXP_MAID, 382 + __IFLA_BRIDGE_CFM_CC_CONFIG_MAX, 383 + }; 384 + 385 + #define IFLA_BRIDGE_CFM_CC_CONFIG_MAX (__IFLA_BRIDGE_CFM_CC_CONFIG_MAX - 1) 386 + 387 + enum { 388 + IFLA_BRIDGE_CFM_CC_PEER_MEP_UNSPEC, 389 + IFLA_BRIDGE_CFM_CC_PEER_MEP_INSTANCE, 390 + IFLA_BRIDGE_CFM_CC_PEER_MEPID, 391 + __IFLA_BRIDGE_CFM_CC_PEER_MEP_MAX, 392 + }; 393 + 394 + #define IFLA_BRIDGE_CFM_CC_PEER_MEP_MAX (__IFLA_BRIDGE_CFM_CC_PEER_MEP_MAX - 1) 395 + 396 + enum { 397 + IFLA_BRIDGE_CFM_CC_RDI_UNSPEC, 398 + IFLA_BRIDGE_CFM_CC_RDI_INSTANCE, 399 + IFLA_BRIDGE_CFM_CC_RDI_RDI, 400 + __IFLA_BRIDGE_CFM_CC_RDI_MAX, 401 + }; 402 + 403 + #define IFLA_BRIDGE_CFM_CC_RDI_MAX (__IFLA_BRIDGE_CFM_CC_RDI_MAX - 1) 404 + 405 + enum { 406 + IFLA_BRIDGE_CFM_CC_CCM_TX_UNSPEC, 407 + IFLA_BRIDGE_CFM_CC_CCM_TX_INSTANCE, 408 + IFLA_BRIDGE_CFM_CC_CCM_TX_DMAC, 409 + IFLA_BRIDGE_CFM_CC_CCM_TX_SEQ_NO_UPDATE, 410 + IFLA_BRIDGE_CFM_CC_CCM_TX_PERIOD, 411 + IFLA_BRIDGE_CFM_CC_CCM_TX_IF_TLV, 412 + IFLA_BRIDGE_CFM_CC_CCM_TX_IF_TLV_VALUE, 413 + IFLA_BRIDGE_CFM_CC_CCM_TX_PORT_TLV, 414 + IFLA_BRIDGE_CFM_CC_CCM_TX_PORT_TLV_VALUE, 415 + __IFLA_BRIDGE_CFM_CC_CCM_TX_MAX, 416 + }; 417 + 418 + #define IFLA_BRIDGE_CFM_CC_CCM_TX_MAX (__IFLA_BRIDGE_CFM_CC_CCM_TX_MAX - 1) 331 419 332 420 struct bridge_stp_xstats { 333 421 __u64 transition_blk;
+1
include/uapi/linux/rtnetlink.h
··· 779 779 #define RTEXT_FILTER_BRVLAN_COMPRESSED (1 << 2) 780 780 #define RTEXT_FILTER_SKIP_STATS (1 << 3) 781 781 #define RTEXT_FILTER_MRP (1 << 4) 782 + #define RTEXT_FILTER_CFM_CONFIG (1 << 5) 782 783 783 784 /* End of information exported to user level */ 784 785
+1 -1
net/bridge/Makefile
··· 28 28 29 29 bridge-$(CONFIG_BRIDGE_MRP) += br_mrp_switchdev.o br_mrp.o br_mrp_netlink.o 30 30 31 - bridge-$(CONFIG_BRIDGE_CFM) += br_cfm.o 31 + bridge-$(CONFIG_BRIDGE_CFM) += br_cfm.o br_cfm_netlink.o
+5
net/bridge/br_cfm.c
··· 799 799 return 0; 800 800 } 801 801 802 + bool br_cfm_created(struct net_bridge *br) 803 + { 804 + return !hlist_empty(&br->mep_list); 805 + } 806 + 802 807 /* Deletes the CFM instances on a specific bridge port 803 808 */ 804 809 void br_cfm_port_del(struct net_bridge *br, struct net_bridge_port *port)
+453
net/bridge/br_cfm_netlink.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + 3 + #include <net/genetlink.h> 4 + 5 + #include "br_private.h" 6 + #include "br_private_cfm.h" 7 + 8 + static const struct nla_policy 9 + br_cfm_mep_create_policy[IFLA_BRIDGE_CFM_MEP_CREATE_MAX + 1] = { 10 + [IFLA_BRIDGE_CFM_MEP_CREATE_UNSPEC] = { .type = NLA_REJECT }, 11 + [IFLA_BRIDGE_CFM_MEP_CREATE_INSTANCE] = { .type = NLA_U32 }, 12 + [IFLA_BRIDGE_CFM_MEP_CREATE_DOMAIN] = { .type = NLA_U32 }, 13 + [IFLA_BRIDGE_CFM_MEP_CREATE_DIRECTION] = { .type = NLA_U32 }, 14 + [IFLA_BRIDGE_CFM_MEP_CREATE_IFINDEX] = { .type = NLA_U32 }, 15 + }; 16 + 17 + static const struct nla_policy 18 + br_cfm_mep_delete_policy[IFLA_BRIDGE_CFM_MEP_DELETE_MAX + 1] = { 19 + [IFLA_BRIDGE_CFM_MEP_DELETE_UNSPEC] = { .type = NLA_REJECT }, 20 + [IFLA_BRIDGE_CFM_MEP_DELETE_INSTANCE] = { .type = NLA_U32 }, 21 + }; 22 + 23 + static const struct nla_policy 24 + br_cfm_mep_config_policy[IFLA_BRIDGE_CFM_MEP_CONFIG_MAX + 1] = { 25 + [IFLA_BRIDGE_CFM_MEP_CONFIG_UNSPEC] = { .type = NLA_REJECT }, 26 + [IFLA_BRIDGE_CFM_MEP_CONFIG_INSTANCE] = { .type = NLA_U32 }, 27 + [IFLA_BRIDGE_CFM_MEP_CONFIG_UNICAST_MAC] = NLA_POLICY_ETH_ADDR, 28 + [IFLA_BRIDGE_CFM_MEP_CONFIG_MDLEVEL] = NLA_POLICY_MAX(NLA_U32, 7), 29 + [IFLA_BRIDGE_CFM_MEP_CONFIG_MEPID] = NLA_POLICY_MAX(NLA_U32, 0x1FFF), 30 + }; 31 + 32 + static const struct nla_policy 33 + br_cfm_cc_config_policy[IFLA_BRIDGE_CFM_CC_CONFIG_MAX + 1] = { 34 + [IFLA_BRIDGE_CFM_CC_CONFIG_UNSPEC] = { .type = NLA_REJECT }, 35 + [IFLA_BRIDGE_CFM_CC_CONFIG_INSTANCE] = { .type = NLA_U32 }, 36 + [IFLA_BRIDGE_CFM_CC_CONFIG_ENABLE] = { .type = NLA_U32 }, 37 + [IFLA_BRIDGE_CFM_CC_CONFIG_EXP_INTERVAL] = { .type = NLA_U32 }, 38 + [IFLA_BRIDGE_CFM_CC_CONFIG_EXP_MAID] = { 39 + .type = NLA_BINARY, .len = CFM_MAID_LENGTH }, 40 + }; 41 + 42 + static const struct nla_policy 43 + br_cfm_cc_peer_mep_policy[IFLA_BRIDGE_CFM_CC_PEER_MEP_MAX + 1] = { 44 + [IFLA_BRIDGE_CFM_CC_PEER_MEP_UNSPEC] = { .type = NLA_REJECT }, 45 + [IFLA_BRIDGE_CFM_CC_PEER_MEP_INSTANCE] = { .type = NLA_U32 }, 46 + [IFLA_BRIDGE_CFM_CC_PEER_MEPID] = NLA_POLICY_MAX(NLA_U32, 0x1FFF), 47 + }; 48 + 49 + static const struct nla_policy 50 + br_cfm_cc_rdi_policy[IFLA_BRIDGE_CFM_CC_RDI_MAX + 1] = { 51 + [IFLA_BRIDGE_CFM_CC_RDI_UNSPEC] = { .type = NLA_REJECT }, 52 + [IFLA_BRIDGE_CFM_CC_RDI_INSTANCE] = { .type = NLA_U32 }, 53 + [IFLA_BRIDGE_CFM_CC_RDI_RDI] = { .type = NLA_U32 }, 54 + }; 55 + 56 + static const struct nla_policy 57 + br_cfm_cc_ccm_tx_policy[IFLA_BRIDGE_CFM_CC_CCM_TX_MAX + 1] = { 58 + [IFLA_BRIDGE_CFM_CC_CCM_TX_UNSPEC] = { .type = NLA_REJECT }, 59 + [IFLA_BRIDGE_CFM_CC_CCM_TX_INSTANCE] = { .type = NLA_U32 }, 60 + [IFLA_BRIDGE_CFM_CC_CCM_TX_DMAC] = NLA_POLICY_ETH_ADDR, 61 + [IFLA_BRIDGE_CFM_CC_CCM_TX_SEQ_NO_UPDATE] = { .type = NLA_U32 }, 62 + [IFLA_BRIDGE_CFM_CC_CCM_TX_PERIOD] = { .type = NLA_U32 }, 63 + [IFLA_BRIDGE_CFM_CC_CCM_TX_IF_TLV] = { .type = NLA_U32 }, 64 + [IFLA_BRIDGE_CFM_CC_CCM_TX_IF_TLV_VALUE] = { .type = NLA_U8 }, 65 + [IFLA_BRIDGE_CFM_CC_CCM_TX_PORT_TLV] = { .type = NLA_U32 }, 66 + [IFLA_BRIDGE_CFM_CC_CCM_TX_PORT_TLV_VALUE] = { .type = NLA_U8 }, 67 + }; 68 + 69 + static const struct nla_policy 70 + br_cfm_policy[IFLA_BRIDGE_CFM_MAX + 1] = { 71 + [IFLA_BRIDGE_CFM_UNSPEC] = { .type = NLA_REJECT }, 72 + [IFLA_BRIDGE_CFM_MEP_CREATE] = 73 + NLA_POLICY_NESTED(br_cfm_mep_create_policy), 74 + [IFLA_BRIDGE_CFM_MEP_DELETE] = 75 + NLA_POLICY_NESTED(br_cfm_mep_delete_policy), 76 + [IFLA_BRIDGE_CFM_MEP_CONFIG] = 77 + NLA_POLICY_NESTED(br_cfm_mep_config_policy), 78 + [IFLA_BRIDGE_CFM_CC_CONFIG] = 79 + NLA_POLICY_NESTED(br_cfm_cc_config_policy), 80 + [IFLA_BRIDGE_CFM_CC_PEER_MEP_ADD] = 81 + NLA_POLICY_NESTED(br_cfm_cc_peer_mep_policy), 82 + [IFLA_BRIDGE_CFM_CC_PEER_MEP_REMOVE] = 83 + NLA_POLICY_NESTED(br_cfm_cc_peer_mep_policy), 84 + [IFLA_BRIDGE_CFM_CC_RDI] = 85 + NLA_POLICY_NESTED(br_cfm_cc_rdi_policy), 86 + [IFLA_BRIDGE_CFM_CC_CCM_TX] = 87 + NLA_POLICY_NESTED(br_cfm_cc_ccm_tx_policy), 88 + }; 89 + 90 + static int br_mep_create_parse(struct net_bridge *br, struct nlattr *attr, 91 + struct netlink_ext_ack *extack) 92 + { 93 + struct nlattr *tb[IFLA_BRIDGE_CFM_MEP_CREATE_MAX + 1]; 94 + struct br_cfm_mep_create create; 95 + u32 instance; 96 + int err; 97 + 98 + err = nla_parse_nested(tb, IFLA_BRIDGE_CFM_MEP_CREATE_MAX, attr, 99 + br_cfm_mep_create_policy, extack); 100 + if (err) 101 + return err; 102 + 103 + if (!tb[IFLA_BRIDGE_CFM_MEP_CREATE_INSTANCE]) { 104 + NL_SET_ERR_MSG_MOD(extack, "Missing INSTANCE attribute"); 105 + return -EINVAL; 106 + } 107 + if (!tb[IFLA_BRIDGE_CFM_MEP_CREATE_DOMAIN]) { 108 + NL_SET_ERR_MSG_MOD(extack, "Missing DOMAIN attribute"); 109 + return -EINVAL; 110 + } 111 + if (!tb[IFLA_BRIDGE_CFM_MEP_CREATE_DIRECTION]) { 112 + NL_SET_ERR_MSG_MOD(extack, "Missing DIRECTION attribute"); 113 + return -EINVAL; 114 + } 115 + if (!tb[IFLA_BRIDGE_CFM_MEP_CREATE_IFINDEX]) { 116 + NL_SET_ERR_MSG_MOD(extack, "Missing IFINDEX attribute"); 117 + return -EINVAL; 118 + } 119 + 120 + memset(&create, 0, sizeof(create)); 121 + 122 + instance = nla_get_u32(tb[IFLA_BRIDGE_CFM_MEP_CREATE_INSTANCE]); 123 + create.domain = nla_get_u32(tb[IFLA_BRIDGE_CFM_MEP_CREATE_DOMAIN]); 124 + create.direction = nla_get_u32(tb[IFLA_BRIDGE_CFM_MEP_CREATE_DIRECTION]); 125 + create.ifindex = nla_get_u32(tb[IFLA_BRIDGE_CFM_MEP_CREATE_IFINDEX]); 126 + 127 + return br_cfm_mep_create(br, instance, &create, extack); 128 + } 129 + 130 + static int br_mep_delete_parse(struct net_bridge *br, struct nlattr *attr, 131 + struct netlink_ext_ack *extack) 132 + { 133 + struct nlattr *tb[IFLA_BRIDGE_CFM_MEP_DELETE_MAX + 1]; 134 + u32 instance; 135 + int err; 136 + 137 + err = nla_parse_nested(tb, IFLA_BRIDGE_CFM_MEP_DELETE_MAX, attr, 138 + br_cfm_mep_delete_policy, extack); 139 + if (err) 140 + return err; 141 + 142 + if (!tb[IFLA_BRIDGE_CFM_MEP_DELETE_INSTANCE]) { 143 + NL_SET_ERR_MSG_MOD(extack, 144 + "Missing INSTANCE attribute"); 145 + return -EINVAL; 146 + } 147 + 148 + instance = nla_get_u32(tb[IFLA_BRIDGE_CFM_MEP_DELETE_INSTANCE]); 149 + 150 + return br_cfm_mep_delete(br, instance, extack); 151 + } 152 + 153 + static int br_mep_config_parse(struct net_bridge *br, struct nlattr *attr, 154 + struct netlink_ext_ack *extack) 155 + { 156 + struct nlattr *tb[IFLA_BRIDGE_CFM_MEP_CONFIG_MAX + 1]; 157 + struct br_cfm_mep_config config; 158 + u32 instance; 159 + int err; 160 + 161 + err = nla_parse_nested(tb, IFLA_BRIDGE_CFM_MEP_CONFIG_MAX, attr, 162 + br_cfm_mep_config_policy, extack); 163 + if (err) 164 + return err; 165 + 166 + if (!tb[IFLA_BRIDGE_CFM_MEP_CONFIG_INSTANCE]) { 167 + NL_SET_ERR_MSG_MOD(extack, "Missing INSTANCE attribute"); 168 + return -EINVAL; 169 + } 170 + if (!tb[IFLA_BRIDGE_CFM_MEP_CONFIG_UNICAST_MAC]) { 171 + NL_SET_ERR_MSG_MOD(extack, "Missing UNICAST_MAC attribute"); 172 + return -EINVAL; 173 + } 174 + if (!tb[IFLA_BRIDGE_CFM_MEP_CONFIG_MDLEVEL]) { 175 + NL_SET_ERR_MSG_MOD(extack, "Missing MDLEVEL attribute"); 176 + return -EINVAL; 177 + } 178 + if (!tb[IFLA_BRIDGE_CFM_MEP_CONFIG_MEPID]) { 179 + NL_SET_ERR_MSG_MOD(extack, "Missing MEPID attribute"); 180 + return -EINVAL; 181 + } 182 + 183 + memset(&config, 0, sizeof(config)); 184 + 185 + instance = nla_get_u32(tb[IFLA_BRIDGE_CFM_MEP_CONFIG_INSTANCE]); 186 + nla_memcpy(&config.unicast_mac.addr, 187 + tb[IFLA_BRIDGE_CFM_MEP_CONFIG_UNICAST_MAC], 188 + sizeof(config.unicast_mac.addr)); 189 + config.mdlevel = nla_get_u32(tb[IFLA_BRIDGE_CFM_MEP_CONFIG_MDLEVEL]); 190 + config.mepid = nla_get_u32(tb[IFLA_BRIDGE_CFM_MEP_CONFIG_MEPID]); 191 + 192 + return br_cfm_mep_config_set(br, instance, &config, extack); 193 + } 194 + 195 + static int br_cc_config_parse(struct net_bridge *br, struct nlattr *attr, 196 + struct netlink_ext_ack *extack) 197 + { 198 + struct nlattr *tb[IFLA_BRIDGE_CFM_CC_CONFIG_MAX + 1]; 199 + struct br_cfm_cc_config config; 200 + u32 instance; 201 + int err; 202 + 203 + err = nla_parse_nested(tb, IFLA_BRIDGE_CFM_CC_CONFIG_MAX, attr, 204 + br_cfm_cc_config_policy, extack); 205 + if (err) 206 + return err; 207 + 208 + if (!tb[IFLA_BRIDGE_CFM_CC_CONFIG_INSTANCE]) { 209 + NL_SET_ERR_MSG_MOD(extack, "Missing INSTANCE attribute"); 210 + return -EINVAL; 211 + } 212 + if (!tb[IFLA_BRIDGE_CFM_CC_CONFIG_ENABLE]) { 213 + NL_SET_ERR_MSG_MOD(extack, "Missing ENABLE attribute"); 214 + return -EINVAL; 215 + } 216 + if (!tb[IFLA_BRIDGE_CFM_CC_CONFIG_EXP_INTERVAL]) { 217 + NL_SET_ERR_MSG_MOD(extack, "Missing INTERVAL attribute"); 218 + return -EINVAL; 219 + } 220 + if (!tb[IFLA_BRIDGE_CFM_CC_CONFIG_EXP_MAID]) { 221 + NL_SET_ERR_MSG_MOD(extack, "Missing MAID attribute"); 222 + return -EINVAL; 223 + } 224 + 225 + memset(&config, 0, sizeof(config)); 226 + 227 + instance = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_CONFIG_INSTANCE]); 228 + config.enable = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_CONFIG_ENABLE]); 229 + config.exp_interval = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_CONFIG_EXP_INTERVAL]); 230 + nla_memcpy(&config.exp_maid.data, tb[IFLA_BRIDGE_CFM_CC_CONFIG_EXP_MAID], 231 + sizeof(config.exp_maid.data)); 232 + 233 + return br_cfm_cc_config_set(br, instance, &config, extack); 234 + } 235 + 236 + static int br_cc_peer_mep_add_parse(struct net_bridge *br, struct nlattr *attr, 237 + struct netlink_ext_ack *extack) 238 + { 239 + struct nlattr *tb[IFLA_BRIDGE_CFM_CC_PEER_MEP_MAX + 1]; 240 + u32 instance, peer_mep_id; 241 + int err; 242 + 243 + err = nla_parse_nested(tb, IFLA_BRIDGE_CFM_CC_PEER_MEP_MAX, attr, 244 + br_cfm_cc_peer_mep_policy, extack); 245 + if (err) 246 + return err; 247 + 248 + if (!tb[IFLA_BRIDGE_CFM_CC_PEER_MEP_INSTANCE]) { 249 + NL_SET_ERR_MSG_MOD(extack, "Missing INSTANCE attribute"); 250 + return -EINVAL; 251 + } 252 + if (!tb[IFLA_BRIDGE_CFM_CC_PEER_MEPID]) { 253 + NL_SET_ERR_MSG_MOD(extack, "Missing PEER_MEP_ID attribute"); 254 + return -EINVAL; 255 + } 256 + 257 + instance = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_PEER_MEP_INSTANCE]); 258 + peer_mep_id = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_PEER_MEPID]); 259 + 260 + return br_cfm_cc_peer_mep_add(br, instance, peer_mep_id, extack); 261 + } 262 + 263 + static int br_cc_peer_mep_remove_parse(struct net_bridge *br, struct nlattr *attr, 264 + struct netlink_ext_ack *extack) 265 + { 266 + struct nlattr *tb[IFLA_BRIDGE_CFM_CC_PEER_MEP_MAX + 1]; 267 + u32 instance, peer_mep_id; 268 + int err; 269 + 270 + err = nla_parse_nested(tb, IFLA_BRIDGE_CFM_CC_PEER_MEP_MAX, attr, 271 + br_cfm_cc_peer_mep_policy, extack); 272 + if (err) 273 + return err; 274 + 275 + if (!tb[IFLA_BRIDGE_CFM_CC_PEER_MEP_INSTANCE]) { 276 + NL_SET_ERR_MSG_MOD(extack, "Missing INSTANCE attribute"); 277 + return -EINVAL; 278 + } 279 + if (!tb[IFLA_BRIDGE_CFM_CC_PEER_MEPID]) { 280 + NL_SET_ERR_MSG_MOD(extack, "Missing PEER_MEP_ID attribute"); 281 + return -EINVAL; 282 + } 283 + 284 + instance = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_PEER_MEP_INSTANCE]); 285 + peer_mep_id = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_PEER_MEPID]); 286 + 287 + return br_cfm_cc_peer_mep_remove(br, instance, peer_mep_id, extack); 288 + } 289 + 290 + static int br_cc_rdi_parse(struct net_bridge *br, struct nlattr *attr, 291 + struct netlink_ext_ack *extack) 292 + { 293 + struct nlattr *tb[IFLA_BRIDGE_CFM_CC_RDI_MAX + 1]; 294 + u32 instance, rdi; 295 + int err; 296 + 297 + err = nla_parse_nested(tb, IFLA_BRIDGE_CFM_CC_RDI_MAX, attr, 298 + br_cfm_cc_rdi_policy, extack); 299 + if (err) 300 + return err; 301 + 302 + if (!tb[IFLA_BRIDGE_CFM_CC_RDI_INSTANCE]) { 303 + NL_SET_ERR_MSG_MOD(extack, "Missing INSTANCE attribute"); 304 + return -EINVAL; 305 + } 306 + if (!tb[IFLA_BRIDGE_CFM_CC_RDI_RDI]) { 307 + NL_SET_ERR_MSG_MOD(extack, "Missing RDI attribute"); 308 + return -EINVAL; 309 + } 310 + 311 + instance = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_RDI_INSTANCE]); 312 + rdi = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_RDI_RDI]); 313 + 314 + return br_cfm_cc_rdi_set(br, instance, rdi, extack); 315 + } 316 + 317 + static int br_cc_ccm_tx_parse(struct net_bridge *br, struct nlattr *attr, 318 + struct netlink_ext_ack *extack) 319 + { 320 + struct nlattr *tb[IFLA_BRIDGE_CFM_CC_CCM_TX_MAX + 1]; 321 + struct br_cfm_cc_ccm_tx_info tx_info; 322 + u32 instance; 323 + int err; 324 + 325 + err = nla_parse_nested(tb, IFLA_BRIDGE_CFM_CC_CCM_TX_MAX, attr, 326 + br_cfm_cc_ccm_tx_policy, extack); 327 + if (err) 328 + return err; 329 + 330 + if (!tb[IFLA_BRIDGE_CFM_CC_CCM_TX_INSTANCE]) { 331 + NL_SET_ERR_MSG_MOD(extack, "Missing INSTANCE attribute"); 332 + return -EINVAL; 333 + } 334 + if (!tb[IFLA_BRIDGE_CFM_CC_CCM_TX_DMAC]) { 335 + NL_SET_ERR_MSG_MOD(extack, "Missing DMAC attribute"); 336 + return -EINVAL; 337 + } 338 + if (!tb[IFLA_BRIDGE_CFM_CC_CCM_TX_SEQ_NO_UPDATE]) { 339 + NL_SET_ERR_MSG_MOD(extack, "Missing SEQ_NO_UPDATE attribute"); 340 + return -EINVAL; 341 + } 342 + if (!tb[IFLA_BRIDGE_CFM_CC_CCM_TX_PERIOD]) { 343 + NL_SET_ERR_MSG_MOD(extack, "Missing PERIOD attribute"); 344 + return -EINVAL; 345 + } 346 + if (!tb[IFLA_BRIDGE_CFM_CC_CCM_TX_IF_TLV]) { 347 + NL_SET_ERR_MSG_MOD(extack, "Missing IF_TLV attribute"); 348 + return -EINVAL; 349 + } 350 + if (!tb[IFLA_BRIDGE_CFM_CC_CCM_TX_IF_TLV_VALUE]) { 351 + NL_SET_ERR_MSG_MOD(extack, "Missing IF_TLV_VALUE attribute"); 352 + return -EINVAL; 353 + } 354 + if (!tb[IFLA_BRIDGE_CFM_CC_CCM_TX_PORT_TLV]) { 355 + NL_SET_ERR_MSG_MOD(extack, "Missing PORT_TLV attribute"); 356 + return -EINVAL; 357 + } 358 + if (!tb[IFLA_BRIDGE_CFM_CC_CCM_TX_PORT_TLV_VALUE]) { 359 + NL_SET_ERR_MSG_MOD(extack, "Missing PORT_TLV_VALUE attribute"); 360 + return -EINVAL; 361 + } 362 + 363 + memset(&tx_info, 0, sizeof(tx_info)); 364 + 365 + instance = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_RDI_INSTANCE]); 366 + nla_memcpy(&tx_info.dmac.addr, 367 + tb[IFLA_BRIDGE_CFM_CC_CCM_TX_DMAC], 368 + sizeof(tx_info.dmac.addr)); 369 + tx_info.seq_no_update = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_CCM_TX_SEQ_NO_UPDATE]); 370 + tx_info.period = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_CCM_TX_PERIOD]); 371 + tx_info.if_tlv = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_CCM_TX_IF_TLV]); 372 + tx_info.if_tlv_value = nla_get_u8(tb[IFLA_BRIDGE_CFM_CC_CCM_TX_IF_TLV_VALUE]); 373 + tx_info.port_tlv = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_CCM_TX_PORT_TLV]); 374 + tx_info.port_tlv_value = nla_get_u8(tb[IFLA_BRIDGE_CFM_CC_CCM_TX_PORT_TLV_VALUE]); 375 + 376 + return br_cfm_cc_ccm_tx(br, instance, &tx_info, extack); 377 + } 378 + 379 + int br_cfm_parse(struct net_bridge *br, struct net_bridge_port *p, 380 + struct nlattr *attr, int cmd, struct netlink_ext_ack *extack) 381 + { 382 + struct nlattr *tb[IFLA_BRIDGE_CFM_MAX + 1]; 383 + int err; 384 + 385 + /* When this function is called for a port then the br pointer is 386 + * invalid, therefor set the br to point correctly 387 + */ 388 + if (p) 389 + br = p->br; 390 + 391 + err = nla_parse_nested(tb, IFLA_BRIDGE_CFM_MAX, attr, 392 + br_cfm_policy, extack); 393 + if (err) 394 + return err; 395 + 396 + if (tb[IFLA_BRIDGE_CFM_MEP_CREATE]) { 397 + err = br_mep_create_parse(br, tb[IFLA_BRIDGE_CFM_MEP_CREATE], 398 + extack); 399 + if (err) 400 + return err; 401 + } 402 + 403 + if (tb[IFLA_BRIDGE_CFM_MEP_DELETE]) { 404 + err = br_mep_delete_parse(br, tb[IFLA_BRIDGE_CFM_MEP_DELETE], 405 + extack); 406 + if (err) 407 + return err; 408 + } 409 + 410 + if (tb[IFLA_BRIDGE_CFM_MEP_CONFIG]) { 411 + err = br_mep_config_parse(br, tb[IFLA_BRIDGE_CFM_MEP_CONFIG], 412 + extack); 413 + if (err) 414 + return err; 415 + } 416 + 417 + if (tb[IFLA_BRIDGE_CFM_CC_CONFIG]) { 418 + err = br_cc_config_parse(br, tb[IFLA_BRIDGE_CFM_CC_CONFIG], 419 + extack); 420 + if (err) 421 + return err; 422 + } 423 + 424 + if (tb[IFLA_BRIDGE_CFM_CC_PEER_MEP_ADD]) { 425 + err = br_cc_peer_mep_add_parse(br, tb[IFLA_BRIDGE_CFM_CC_PEER_MEP_ADD], 426 + extack); 427 + if (err) 428 + return err; 429 + } 430 + 431 + if (tb[IFLA_BRIDGE_CFM_CC_PEER_MEP_REMOVE]) { 432 + err = br_cc_peer_mep_remove_parse(br, tb[IFLA_BRIDGE_CFM_CC_PEER_MEP_REMOVE], 433 + extack); 434 + if (err) 435 + return err; 436 + } 437 + 438 + if (tb[IFLA_BRIDGE_CFM_CC_RDI]) { 439 + err = br_cc_rdi_parse(br, tb[IFLA_BRIDGE_CFM_CC_RDI], 440 + extack); 441 + if (err) 442 + return err; 443 + } 444 + 445 + if (tb[IFLA_BRIDGE_CFM_CC_CCM_TX]) { 446 + err = br_cc_ccm_tx_parse(br, tb[IFLA_BRIDGE_CFM_CC_CCM_TX], 447 + extack); 448 + if (err) 449 + return err; 450 + } 451 + 452 + return 0; 453 + }
+5
net/bridge/br_netlink.c
··· 700 700 if (err) 701 701 return err; 702 702 break; 703 + case IFLA_BRIDGE_CFM: 704 + err = br_cfm_parse(br, p, attr, cmd, extack); 705 + if (err) 706 + return err; 707 + break; 703 708 } 704 709 } 705 710
+16 -1
net/bridge/br_private.h
··· 1459 1459 1460 1460 #endif 1461 1461 1462 - /* br_mrp.c */ 1462 + /* br_cfm.c */ 1463 1463 #if IS_ENABLED(CONFIG_BRIDGE_CFM) 1464 + int br_cfm_parse(struct net_bridge *br, struct net_bridge_port *p, 1465 + struct nlattr *attr, int cmd, struct netlink_ext_ack *extack); 1466 + bool br_cfm_created(struct net_bridge *br); 1464 1467 void br_cfm_port_del(struct net_bridge *br, struct net_bridge_port *p); 1465 1468 #else 1469 + static inline int br_cfm_parse(struct net_bridge *br, struct net_bridge_port *p, 1470 + struct nlattr *attr, int cmd, 1471 + struct netlink_ext_ack *extack) 1472 + { 1473 + return -EOPNOTSUPP; 1474 + } 1475 + 1476 + static inline bool br_cfm_created(struct net_bridge *br) 1477 + { 1478 + return false; 1479 + } 1480 + 1466 1481 static inline void br_cfm_port_del(struct net_bridge *br, 1467 1482 struct net_bridge_port *p) 1468 1483 {