Skip to content

Commit 2a67ab9

Browse files
committed
Merge branch 'bridge-mrp-Add-support-for-MRA-role'
Horatiu Vultur says: ==================== bridge: mrp: Add support for MRA role This patch series extends the MRP with the MRA role. A node that has the MRA role can behave as a MRM or as a MRC. In case there are multiple nodes in the topology that has the MRA role then only one node can behave as MRM and all the others need to be have as MRC. The node that has the higher priority(lower value) will behave as MRM. A node that has the MRA role and behaves as MRC, it just needs to forward the MRP_Test frames between the ring ports but also it needs to detect in case it stops receiving MRP_Test frames. In that case it would try to behave as MRM. v2: - add new patch that fixes sparse warnings - fix parsing of prio attribute ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 3e1c684 + c6676e7 commit 2a67ab9

File tree

7 files changed

+182
-33
lines changed

7 files changed

+182
-33
lines changed

include/net/switchdev.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ struct switchdev_obj_mrp {
116116
struct net_device *p_port;
117117
struct net_device *s_port;
118118
u32 ring_id;
119+
u16 prio;
119120
};
120121

121122
#define SWITCHDEV_OBJ_MRP(OBJ) \
@@ -129,6 +130,7 @@ struct switchdev_obj_ring_test_mrp {
129130
u8 max_miss;
130131
u32 ring_id;
131132
u32 period;
133+
bool monitor;
132134
};
133135

134136
#define SWITCHDEV_OBJ_RING_TEST_MRP(OBJ) \

include/uapi/linux/if_bridge.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ enum {
176176
IFLA_BRIDGE_MRP_INSTANCE_RING_ID,
177177
IFLA_BRIDGE_MRP_INSTANCE_P_IFINDEX,
178178
IFLA_BRIDGE_MRP_INSTANCE_S_IFINDEX,
179+
IFLA_BRIDGE_MRP_INSTANCE_PRIO,
179180
__IFLA_BRIDGE_MRP_INSTANCE_MAX,
180181
};
181182

@@ -221,6 +222,7 @@ enum {
221222
IFLA_BRIDGE_MRP_START_TEST_INTERVAL,
222223
IFLA_BRIDGE_MRP_START_TEST_MAX_MISS,
223224
IFLA_BRIDGE_MRP_START_TEST_PERIOD,
225+
IFLA_BRIDGE_MRP_START_TEST_MONITOR,
224226
__IFLA_BRIDGE_MRP_START_TEST_MAX,
225227
};
226228

@@ -230,6 +232,7 @@ struct br_mrp_instance {
230232
__u32 ring_id;
231233
__u32 p_ifindex;
232234
__u32 s_ifindex;
235+
__u16 prio;
233236
};
234237

235238
struct br_mrp_ring_state {
@@ -247,6 +250,7 @@ struct br_mrp_start_test {
247250
__u32 interval;
248251
__u32 max_miss;
249252
__u32 period;
253+
__u32 monitor;
250254
};
251255

252256
struct bridge_stp_xstats {

include/uapi/linux/mrp_bridge.h

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,14 @@
1111
#define MRP_DOMAIN_UUID_LENGTH 16
1212
#define MRP_VERSION 1
1313
#define MRP_FRAME_PRIO 7
14+
#define MRP_OUI_LENGTH 3
15+
#define MRP_MANUFACTURE_DATA_LENGTH 2
1416

1517
enum br_mrp_ring_role_type {
1618
BR_MRP_RING_ROLE_DISABLED,
1719
BR_MRP_RING_ROLE_MRC,
1820
BR_MRP_RING_ROLE_MRM,
21+
BR_MRP_RING_ROLE_MRA,
1922
};
2023

2124
enum br_mrp_ring_state_type {
@@ -43,42 +46,77 @@ enum br_mrp_tlv_header_type {
4346
BR_MRP_TLV_HEADER_RING_TOPO = 0x3,
4447
BR_MRP_TLV_HEADER_RING_LINK_DOWN = 0x4,
4548
BR_MRP_TLV_HEADER_RING_LINK_UP = 0x5,
49+
BR_MRP_TLV_HEADER_OPTION = 0x7f,
50+
};
51+
52+
enum br_mrp_sub_tlv_header_type {
53+
BR_MRP_SUB_TLV_HEADER_TEST_MGR_NACK = 0x1,
54+
BR_MRP_SUB_TLV_HEADER_TEST_PROPAGATE = 0x2,
55+
BR_MRP_SUB_TLV_HEADER_TEST_AUTO_MGR = 0x3,
4656
};
4757

4858
struct br_mrp_tlv_hdr {
4959
__u8 type;
5060
__u8 length;
5161
};
5262

63+
struct br_mrp_sub_tlv_hdr {
64+
__u8 type;
65+
__u8 length;
66+
};
67+
5368
struct br_mrp_end_hdr {
5469
struct br_mrp_tlv_hdr hdr;
5570
};
5671

5772
struct br_mrp_common_hdr {
58-
__u16 seq_id;
73+
__be16 seq_id;
5974
__u8 domain[MRP_DOMAIN_UUID_LENGTH];
6075
};
6176

6277
struct br_mrp_ring_test_hdr {
63-
__u16 prio;
78+
__be16 prio;
6479
__u8 sa[ETH_ALEN];
65-
__u16 port_role;
66-
__u16 state;
67-
__u16 transitions;
68-
__u32 timestamp;
80+
__be16 port_role;
81+
__be16 state;
82+
__be16 transitions;
83+
__be32 timestamp;
6984
};
7085

7186
struct br_mrp_ring_topo_hdr {
72-
__u16 prio;
87+
__be16 prio;
7388
__u8 sa[ETH_ALEN];
74-
__u16 interval;
89+
__be16 interval;
7590
};
7691

7792
struct br_mrp_ring_link_hdr {
7893
__u8 sa[ETH_ALEN];
79-
__u16 port_role;
80-
__u16 interval;
81-
__u16 blocked;
94+
__be16 port_role;
95+
__be16 interval;
96+
__be16 blocked;
97+
};
98+
99+
struct br_mrp_sub_opt_hdr {
100+
__u8 type;
101+
__u8 manufacture_data[MRP_MANUFACTURE_DATA_LENGTH];
102+
};
103+
104+
struct br_mrp_test_mgr_nack_hdr {
105+
__be16 prio;
106+
__u8 sa[ETH_ALEN];
107+
__be16 other_prio;
108+
__u8 other_sa[ETH_ALEN];
109+
};
110+
111+
struct br_mrp_test_prop_hdr {
112+
__be16 prio;
113+
__u8 sa[ETH_ALEN];
114+
__be16 other_prio;
115+
__u8 other_sa[ETH_ALEN];
116+
};
117+
118+
struct br_mrp_oui_hdr {
119+
__u8 oui[MRP_OUI_LENGTH];
82120
};
83121

84122
#endif

net/bridge/br_mrp.c

Lines changed: 108 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ static struct sk_buff *br_mrp_alloc_test_skb(struct br_mrp *mrp,
147147
br_mrp_skb_tlv(skb, BR_MRP_TLV_HEADER_RING_TEST, sizeof(*hdr));
148148
hdr = skb_put(skb, sizeof(*hdr));
149149

150-
hdr->prio = cpu_to_be16(MRP_DEFAULT_PRIO);
150+
hdr->prio = cpu_to_be16(mrp->prio);
151151
ether_addr_copy(hdr->sa, p->br->dev->dev_addr);
152152
hdr->port_role = cpu_to_be16(port_role);
153153
hdr->state = cpu_to_be16(mrp->ring_state);
@@ -160,6 +160,16 @@ static struct sk_buff *br_mrp_alloc_test_skb(struct br_mrp *mrp,
160160
return skb;
161161
}
162162

163+
/* This function is continuously called in the following cases:
164+
* - when node role is MRM, in this case test_monitor is always set to false
165+
* because it needs to notify the userspace that the ring is open and needs to
166+
* send MRP_Test frames
167+
* - when node role is MRA, there are 2 subcases:
168+
* - when MRA behaves as MRM, in this case is similar with MRM role
169+
* - when MRA behaves as MRC, in this case test_monitor is set to true,
170+
* because it needs to detect when it stops seeing MRP_Test frames
171+
* from MRM node but it doesn't need to send MRP_Test frames.
172+
*/
163173
static void br_mrp_test_work_expired(struct work_struct *work)
164174
{
165175
struct delayed_work *del_work = to_delayed_work(work);
@@ -177,34 +187,46 @@ static void br_mrp_test_work_expired(struct work_struct *work)
177187
/* Notify that the ring is open only if the ring state is
178188
* closed, otherwise it would continue to notify at every
179189
* interval.
190+
* Also notify that the ring is open when the node has the
191+
* role MRA and behaves as MRC. The reason is that the
192+
* userspace needs to know when the MRM stopped sending
193+
* MRP_Test frames so that the current node to try to take
194+
* the role of a MRM.
180195
*/
181-
if (mrp->ring_state == BR_MRP_RING_STATE_CLOSED)
196+
if (mrp->ring_state == BR_MRP_RING_STATE_CLOSED ||
197+
mrp->test_monitor)
182198
notify_open = true;
183199
}
184200

185201
rcu_read_lock();
186202

187203
p = rcu_dereference(mrp->p_port);
188204
if (p) {
189-
skb = br_mrp_alloc_test_skb(mrp, p, BR_MRP_PORT_ROLE_PRIMARY);
190-
if (!skb)
191-
goto out;
192-
193-
skb_reset_network_header(skb);
194-
dev_queue_xmit(skb);
205+
if (!mrp->test_monitor) {
206+
skb = br_mrp_alloc_test_skb(mrp, p,
207+
BR_MRP_PORT_ROLE_PRIMARY);
208+
if (!skb)
209+
goto out;
210+
211+
skb_reset_network_header(skb);
212+
dev_queue_xmit(skb);
213+
}
195214

196215
if (notify_open && !mrp->ring_role_offloaded)
197216
br_mrp_port_open(p->dev, true);
198217
}
199218

200219
p = rcu_dereference(mrp->s_port);
201220
if (p) {
202-
skb = br_mrp_alloc_test_skb(mrp, p, BR_MRP_PORT_ROLE_SECONDARY);
203-
if (!skb)
204-
goto out;
205-
206-
skb_reset_network_header(skb);
207-
dev_queue_xmit(skb);
221+
if (!mrp->test_monitor) {
222+
skb = br_mrp_alloc_test_skb(mrp, p,
223+
BR_MRP_PORT_ROLE_SECONDARY);
224+
if (!skb)
225+
goto out;
226+
227+
skb_reset_network_header(skb);
228+
dev_queue_xmit(skb);
229+
}
208230

209231
if (notify_open && !mrp->ring_role_offloaded)
210232
br_mrp_port_open(p->dev, true);
@@ -227,7 +249,7 @@ static void br_mrp_del_impl(struct net_bridge *br, struct br_mrp *mrp)
227249

228250
/* Stop sending MRP_Test frames */
229251
cancel_delayed_work_sync(&mrp->test_work);
230-
br_mrp_switchdev_send_ring_test(br, mrp, 0, 0, 0);
252+
br_mrp_switchdev_send_ring_test(br, mrp, 0, 0, 0, 0);
231253

232254
br_mrp_switchdev_del(br, mrp);
233255

@@ -290,6 +312,7 @@ int br_mrp_add(struct net_bridge *br, struct br_mrp_instance *instance)
290312
return -ENOMEM;
291313

292314
mrp->ring_id = instance->ring_id;
315+
mrp->prio = instance->prio;
293316

294317
p = br_mrp_get_port(br, instance->p_ifindex);
295318
spin_lock_bh(&br->lock);
@@ -451,8 +474,8 @@ int br_mrp_set_ring_role(struct net_bridge *br,
451474
return 0;
452475
}
453476

454-
/* Start to generate MRP test frames, the frames are generated by HW and if it
455-
* fails, they are generated by the SW.
477+
/* Start to generate or monitor MRP test frames, the frames are generated by
478+
* HW and if it fails, they are generated by the SW.
456479
* note: already called with rtnl_lock
457480
*/
458481
int br_mrp_start_test(struct net_bridge *br,
@@ -463,16 +486,18 @@ int br_mrp_start_test(struct net_bridge *br,
463486
if (!mrp)
464487
return -EINVAL;
465488

466-
/* Try to push it to the HW and if it fails then continue to generate in
467-
* SW and if that also fails then return error
489+
/* Try to push it to the HW and if it fails then continue with SW
490+
* implementation and if that also fails then return error.
468491
*/
469492
if (!br_mrp_switchdev_send_ring_test(br, mrp, test->interval,
470-
test->max_miss, test->period))
493+
test->max_miss, test->period,
494+
test->monitor))
471495
return 0;
472496

473497
mrp->test_interval = test->interval;
474498
mrp->test_end = jiffies + usecs_to_jiffies(test->period);
475499
mrp->test_max_miss = test->max_miss;
500+
mrp->test_monitor = test->monitor;
476501
mrp->test_count_miss = 0;
477502
queue_delayed_work(system_wq, &mrp->test_work,
478503
usecs_to_jiffies(test->interval));
@@ -509,6 +534,57 @@ static void br_mrp_mrm_process(struct br_mrp *mrp, struct net_bridge_port *port,
509534
br_mrp_port_open(port->dev, false);
510535
}
511536

537+
/* Determin if the test hdr has a better priority than the node */
538+
static bool br_mrp_test_better_than_own(struct br_mrp *mrp,
539+
struct net_bridge *br,
540+
const struct br_mrp_ring_test_hdr *hdr)
541+
{
542+
u16 prio = be16_to_cpu(hdr->prio);
543+
544+
if (prio < mrp->prio ||
545+
(prio == mrp->prio &&
546+
ether_addr_to_u64(hdr->sa) < ether_addr_to_u64(br->dev->dev_addr)))
547+
return true;
548+
549+
return false;
550+
}
551+
552+
/* Process only MRP Test frame. All the other MRP frames are processed by
553+
* userspace application
554+
* note: already called with rcu_read_lock
555+
*/
556+
static void br_mrp_mra_process(struct br_mrp *mrp, struct net_bridge *br,
557+
struct net_bridge_port *port,
558+
struct sk_buff *skb)
559+
{
560+
const struct br_mrp_ring_test_hdr *test_hdr;
561+
struct br_mrp_ring_test_hdr _test_hdr;
562+
const struct br_mrp_tlv_hdr *hdr;
563+
struct br_mrp_tlv_hdr _hdr;
564+
565+
/* Each MRP header starts with a version field which is 16 bits.
566+
* Therefore skip the version and get directly the TLV header.
567+
*/
568+
hdr = skb_header_pointer(skb, sizeof(uint16_t), sizeof(_hdr), &_hdr);
569+
if (!hdr)
570+
return;
571+
572+
if (hdr->type != BR_MRP_TLV_HEADER_RING_TEST)
573+
return;
574+
575+
test_hdr = skb_header_pointer(skb, sizeof(uint16_t) + sizeof(_hdr),
576+
sizeof(_test_hdr), &_test_hdr);
577+
if (!test_hdr)
578+
return;
579+
580+
/* Only frames that have a better priority than the node will
581+
* clear the miss counter because otherwise the node will need to behave
582+
* as MRM.
583+
*/
584+
if (br_mrp_test_better_than_own(mrp, br, test_hdr))
585+
mrp->test_count_miss = 0;
586+
}
587+
512588
/* This will just forward the frame to the other mrp ring port(MRC role) or will
513589
* not do anything.
514590
* note: already called with rcu_read_lock
@@ -545,6 +621,18 @@ static int br_mrp_rcv(struct net_bridge_port *p,
545621
return 1;
546622
}
547623

624+
/* If the role is MRA then don't forward the frames if it behaves as
625+
* MRM node
626+
*/
627+
if (mrp->ring_role == BR_MRP_RING_ROLE_MRA) {
628+
if (!mrp->test_monitor) {
629+
br_mrp_mrm_process(mrp, p, skb);
630+
return 1;
631+
}
632+
633+
br_mrp_mra_process(mrp, br, p, skb);
634+
}
635+
548636
/* Clone the frame and forward it on the other MRP port */
549637
nskb = skb_clone(skb, GFP_ATOMIC);
550638
if (!nskb)

0 commit comments

Comments
 (0)