func (r *L2Switch) processPacket(finder network.Finder, ingress *network.Port, eth *protocol.Ethernet) (drop bool, err error) { r.log.Debug(fmt.Sprintf("L2Switch: PACKET_IN.. Ingress=%v, SrcMAC=%v, DstMAC=%v", ingress.ID(), eth.SrcMAC, eth.DstMAC)) packet, err := eth.MarshalBinary() if err != nil { return false, err } // Broadcast? if isBroadcast(eth) { r.log.Debug(fmt.Sprintf("L2Switch: broadcasting.. SrcMAC=%v, DstMAC=%v", eth.SrcMAC, eth.DstMAC)) return true, r.stormCtrl.broadcast(ingress, packet) } dstNode, err := finder.Node(eth.DstMAC) if err != nil { return true, fmt.Errorf("locating a node (MAC=%v): %v", eth.DstMAC, err) } // Unknown node? if dstNode == nil { r.log.Debug(fmt.Sprintf("L2Switch: unknown node! dropping.. SrcMAC=%v, DstMAC=%v", eth.SrcMAC, eth.DstMAC)) return true, nil } // Disconnected node? port := dstNode.Port().Value() if port.IsPortDown() || port.IsLinkDown() { r.log.Debug(fmt.Sprintf("L2Switch: disconnected node! dropping.. SrcMAC=%v, DstMAC=%v", eth.SrcMAC, eth.DstMAC)) return true, nil } param := switchParam{} // Check whether src and dst nodes reside on a same switch device if ingress.Device().ID() == dstNode.Port().Device().ID() { param = switchParam{ finder: finder, ethernet: eth, ingress: ingress, egress: dstNode.Port(), rawPacket: packet, } } else { path := finder.Path(ingress.Device().ID(), dstNode.Port().Device().ID()) if len(path) == 0 { r.log.Debug(fmt.Sprintf("L2Switch: empty path.. dropping SrcMAC=%v, DstMAC=%v", eth.SrcMAC, eth.DstMAC)) return true, nil } egress := path[0][0] // Drop this packet if it goes back to the ingress port to avoid duplicated packet routing if ingress.Number() == egress.Number() { r.log.Debug(fmt.Sprintf("L2Switch: ignore routing path that goes back to the ingress port (SrcMAC=%v, DstMAC=%v)", eth.SrcMAC, eth.DstMAC)) return true, nil } param = switchParam{ finder: finder, ethernet: eth, ingress: ingress, egress: egress, rawPacket: packet, } } return true, r.switching(param) }