@@ -340,6 +340,91 @@ static void rbr_recv(struct sk_buff *skb, u16 vid)
}
return;
}
+ /* Multi-destination frame:
+ * Check if received multi-destination frame from an
+ * adjacency in the distribution tree rooted at egress nick
+ * indicated in the frame header
+ */
+ dest = rbr_find_node(rbr, trh->th_egressnick);
+ if (unlikely(dest == NULL)) {
+ pr_warn_ratelimited
+ ("rbr_recv: mulicast with unknown destination\n");
+ goto recv_drop;
+ }
+ for (idx = 0; idx < dest->rbr_ni->adjcount; idx++) {
+ adjnick = RBR_NI_ADJNICK(dest->rbr_ni, idx);
+ adj = rbr_find_node(rbr, adjnick);
+ if (adj == NULL)
+ continue;
+ if (memcmp(adj->rbr_ni->adjsnpa, srcaddr, ETH_ALEN) == 0) {
+ rbr_node_put(adj);
+ break;
+ }
+ rbr_node_put(adj);
+ }
+
+ if (unlikely(idx >= dest->rbr_ni->adjcount)) {
+ pr_warn_ratelimited("rbr_recv: multicast unknow mac source\n");
+ rbr_node_put(dest);
+ goto recv_drop;
+ }
+
+ /* Reverse path forwarding check.
+ * Check if the ingress RBridge that has forwarded
+ * the frame advertised the use of the distribution tree specified
+ * in the egress nick
+ */
+ source_node = rbr_find_node(rbr, trh->th_ingressnick);
+ if (unlikely(source_node == NULL)) {
+ pr_warn_ratelimited
+ ("rbr_recv: reverse path forwarding check failed\n");
+ rbr_node_put(dest);
+ goto recv_drop;
+ }
+ for (idx = 0; idx < source_node->rbr_ni->dtrootcount; idx++) {
+ if (RBR_NI_DTROOTNICK(source_node->rbr_ni, idx) ==
+ trh->th_egressnick)
+ break;
+ }
+
+ if (idx >= source_node->rbr_ni->dtrootcount) {
+ /* Allow receipt of forwarded frame with the highest
+ * tree root RBridge as the egress RBridge when the
+ * ingress RBridge has not advertised the use of any
+ * distribution trees.
+ */
+ if (source_node->rbr_ni->dtrootcount != 0 ||
+ trh->th_egressnick != dtrNick) {
+ rbr_node_put(source_node);
+ rbr_node_put(dest);
+ goto recv_drop;
+ }
+ }
+
+ /* Check hop count before doing any forwarding */
+ if (unlikely(trill_get_hopcount(trill_flags) == 0)) {
+ pr_warn_ratelimited
+ ("rbr_recv: multicast hop count limit reached\n");
+ rbr_node_put(dest);
+ goto recv_drop;
+ }
+ /* Forward frame using the distribution tree specified by egress nick */
+ rbr_node_put(source_node);
+ rbr_node_put(dest);
+
+ /* skb2 will be multi forwarded and skb will be locally decaps */
+ if (unlikely((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL)) {
+ p->br->dev->stats.tx_dropped++;
+ pr_warn_ratelimited("rbr_recv: multicast skb_clone failed\n");
+ goto recv_drop;
+ }
+
+ /* TODO multi forwarding */
+
+ /*
+ * Send de-capsulated frame locally
+ */
+ /* TODO decapsulate function */
return;