func (r *ProxyARP) OnPacketIn(finder network.Finder, ingress *network.Port, eth *protocol.Ethernet) error { // ARP? if eth.Type != 0x0806 { return r.BaseProcessor.OnPacketIn(finder, ingress, eth) } r.log.Debug(fmt.Sprintf("ProxyARP: received ARP packet.. ingress=%v, srcEthMAC=%v, dstEthMAC=%v", ingress.ID(), eth.SrcMAC, eth.DstMAC)) arp := new(protocol.ARP) if err := arp.UnmarshalBinary(eth.Payload); err != nil { return err } // Drop ARP announcement if isARPAnnouncement(arp) { // We don't allow a host sends ARP announcement to the network. This controller only can send it, // and we will flood the announcement to all switch devices using PACKET_OUT when we need it. r.log.Info(fmt.Sprintf("ProxyARP: drop ARP announcements.. ingress=%v (%v)", ingress.ID(), arp)) return nil } // ARP request? if arp.Operation != 1 { // Drop all ARP packets whose type is not a reqeust. r.log.Info(fmt.Sprintf("ProxyARP: drop ARP packet whose type is not a request.. ingress=%v (%v)", ingress.ID(), arp)) return nil } mac, ok, err := r.db.MAC(arp.TPA) if err != nil { return err } if !ok { r.log.Debug(fmt.Sprintf("ProxyARP: drop the ARP request for unknown host (%v)", arp.TPA)) // Unknown hosts. Drop the packet. return nil } r.log.Debug(fmt.Sprintf("ProxyARP: ARP request for %v (%v)", arp.TPA, mac)) reply, err := makeARPReply(arp, mac) if err != nil { return err } r.log.Debug(fmt.Sprintf("ProxyARP: sending ARP reply to %v..", ingress.ID())) return sendARPReply(ingress, reply) }
func (r *flooder) flood(ingress *network.Port, packet []byte) error { f := ingress.Device().Factory() inPort := openflow.NewInPort() inPort.SetValue(ingress.Number()) outPort := openflow.NewOutPort() outPort.SetFlood() action, err := f.NewAction() if err != nil { return err } action.SetOutPort(outPort) out, err := f.NewPacketOut() if err != nil { return err } out.SetInPort(inPort) out.SetAction(action) out.SetData(packet) return ingress.Device().SendMessage(out) }
func (r *BaseProcessor) PacketOut(egress *network.Port, packet []byte) error { f := egress.Device().Factory() inPort := openflow.NewInPort() inPort.SetController() outPort := openflow.NewOutPort() outPort.SetValue(egress.Number()) action, err := f.NewAction() if err != nil { return err } action.SetOutPort(outPort) out, err := f.NewPacketOut() if err != nil { return err } out.SetInPort(inPort) out.SetAction(action) out.SetData(packet) return egress.Device().SendMessage(out) }
func (r *ProxyARP) OnPortDown(finder network.Finder, port *network.Port) error { dpid, err := strconv.ParseUint(port.Device().ID(), 10, 64) if err != nil { r.log.Err(fmt.Sprintf("ProxyARP: invalid switch DPID: %v", port.Device().ID())) return r.BaseProcessor.OnPortDown(finder, port) } vips, err := r.db.TogglePortVIP(dpid, uint16(port.Number())) if err != nil { r.log.Err(fmt.Sprintf("ProxyARP: failed to toggle VIP hosts: %v", err)) return r.BaseProcessor.OnPortDown(finder, port) } r.broadcastARPAnnouncement(finder, vips) return r.BaseProcessor.OnPortDown(finder, port) }
func (r *L2Switch) OnPortDown(finder network.Finder, port *network.Port) error { r.log.Debug(fmt.Sprintf("L2Switch: port down! removing all flows heading to that port (%v)..", port.ID())) device := port.Device() factory := device.Factory() // Wildcard match match, err := factory.NewMatch() if err != nil { return err } outPort := openflow.NewOutPort() outPort.SetValue(port.Number()) if err := device.RemoveFlow(match, outPort); err != nil { return fmt.Errorf("removing flows heading to port %v: %v", port.ID(), err) } return r.BaseProcessor.OnPortDown(finder, port) }
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) }