diff mbox

[RFC,v2,18/21] net: rbridge: add rbr_fwd

Message ID 1441122196-11662-19-git-send-email-ahmed@gandi.net
State RFC, archived
Delegated to: David Miller
Headers show

Commit Message

Ahmed Amamou Sept. 1, 2015, 3:43 p.m. UTC
add rbridge forward function
packets arriving to rbr_fwd should be already encapsulated and correct
egress
and ingress nickname should be already assigned
rbr_fwd function will assign correct source and destination outer MAC
addresses
according to which port will send the frame and next hop to reach
the engress nickname
Nexthope to reach the egress will be found in node database

Signed-off-by: Ahmed Amamou <ahmed@gandi.net>
Signed-off-by: Kamel Haddadou <kamel@gandi.net>
Signed-off-by: William Dauchy <william@gandi.net>
Signed-off-by: François Cachereul <f.cachereul@alphalink.fr>
---
 net/bridge/rbr.c | 46 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 44 insertions(+), 2 deletions(-)
diff mbox

Patch

diff --git a/net/bridge/rbr.c b/net/bridge/rbr.c
index c04c05a..ab71e6b 100644
--- a/net/bridge/rbr.c
+++ b/net/bridge/rbr.c
@@ -172,6 +172,48 @@  static bool add_header(struct sk_buff *skb, uint16_t ingressnick,
 	return 0;
 }
 
+static void rbr_fwd(struct net_bridge_port *p, struct sk_buff *skb,
+		    u16 adj_nick, u16 vid)
+{
+	struct rbr_node *adj;
+	struct trill_hdr *trh;
+	struct ethhdr *outerethhdr;
+	struct net *net = dev_net(p->dev);
+	struct net_device *outdev;
+	struct net_bridge_port *outp;
+
+	adj = rbr_find_node(p->br->rbr, adj_nick);
+	if (unlikely(!adj || !adj->rbr_ni)) {
+		pr_warn_ratelimited("rbr_fwd: unable to find adjacent RBridge\n");
+		goto dest_fwd_fail;
+	}
+	outdev = dev_get_by_index_rcu(net, adj->rbr_ni->linkid);
+	if (!outdev) {
+		pr_warn_ratelimited("rbr_fwd: cannot find source port device for forwrding\n");
+		goto dest_fwd_fail;
+	}
+
+	trh = (struct trill_hdr *)skb->data;
+	trillhdr_dec_hopcount(trh);
+	outerethhdr = eth_hdr(skb);
+
+	/* change outer ether header */
+	/* bridge becomes the source_port address in outeretherhdr */
+	outp = br_port_get_rcu(outdev);
+	ether_addr_copy(outerethhdr->h_source, outp->dev->dev_addr);
+	/* dist port becomes dest address in outeretherhdr */
+	ether_addr_copy(outerethhdr->h_dest, adj->rbr_ni->adjsnpa);
+	rbr_node_put(adj);
+	skb->dev = p->br->dev;
+	br_forward(outp, skb, NULL);
+	return;
+
+dest_fwd_fail:
+	if (likely(p && p->br))
+		p->br->dev->stats.tx_dropped++;
+	kfree_skb(skb);
+}
+
 static void rbr_encaps(struct sk_buff *skb, u16 egressnick, u16 vid)
 {
 	u16 local_nick;
@@ -234,7 +276,7 @@  static void rbr_encaps(struct sk_buff *skb, u16 egressnick, u16 vid)
 	} else {
 		if (unlikely(add_header(skb, local_nick, egressnick, 0)))
 			goto encaps_drop;
-		/* TODO simple forwarding */
+		rbr_fwd(p, skb, egressnick, vid);
 	}
 	return;
  encaps_drop:
@@ -373,7 +415,7 @@  static void rbr_recv(struct sk_buff *skb, u16 vid)
 		} else if (likely(trill_get_hopcount(trill_flags))) {
 			br_fdb_update(p->br, p, eth_hdr(skb)->h_source,
 				      vid, false);
-			/* TODO simple forwarding */
+			rbr_fwd(p, skb, trh->th_egressnick, vid);
 		} else {
 			pr_warn_ratelimited("rbr_recv: hop count limit reached\n");
 			goto recv_drop;