// sendGARP sends GARP for the specified IP, MAC func (self *Vxlan) sendGARP(ip net.IP, mac net.HardwareAddr, vni uint64) error { // NOTE: Enable this when EVPN support is added. if !VXLAN_GARP_SUPPORTED { return nil } pktOut := BuildGarpPkt(ip, mac, 0) tunnelIdField := openflow13.NewTunnelIdField(vni) setTunnelAction := openflow13.NewActionSetField(*tunnelIdField) // Add set tunnel action to the instruction pktOut.AddAction(setTunnelAction) self.agent.vtepTableMutex.RLock() for _, vtepPort := range self.agent.vtepTable { log.Debugf("Sending to Vtep port: %+v", *vtepPort) pktOut.AddAction(openflow13.NewActionOutput(*vtepPort)) } self.agent.vtepTableMutex.RUnlock() // Send it out self.ofSwitch.Send(pktOut) self.agent.incrStats("GarpPktSent") return nil }
// Install a group entry in OF switch func (self *Flood) install() error { groupMod := openflow13.NewGroupMod() groupMod.GroupId = self.GroupId // Change the OP to modify if it was already installed if self.isInstalled { groupMod.Command = openflow13.OFPGC_MODIFY } // OF type for flood list groupMod.Type = openflow13.OFPGT_ALL // Loop thru all output ports and add it to group bucket for _, output := range self.FloodList { // Get the output action from output entry act := output.outPort.GetOutAction() if act != nil { // Create a new bucket for each port bkt := openflow13.NewBucket() // Set tunnel Id if required if output.isTunnel { tunnelField := openflow13.NewTunnelIdField(output.tunnelId) setTunnel := openflow13.NewActionSetField(*tunnelField) bkt.AddAction(setTunnel) } // Always remove vlan tag popVlan := openflow13.NewActionPopVlan() bkt.AddAction(popVlan) // Add the output action to the bucket bkt.AddAction(act) // Add the bucket to group groupMod.AddBucket(*bkt) } } log.Infof("Installing Group entry: %+v", groupMod) // Send it to the switch self.Switch.Send(groupMod) // Mark it as installed self.isInstalled = true return nil }
// Install all flow actions func (self *Flow) installFlowActions(flowMod *openflow13.FlowMod, instr openflow13.Instruction) error { var actInstr openflow13.Instruction var addActn bool = false // Create a apply_action instruction to be used if its not already created switch instr.(type) { case *openflow13.InstrActions: actInstr = instr default: actInstr = openflow13.NewInstrApplyActions() } // Loop thru all actions for _, flowAction := range self.flowActions { switch flowAction.actionType { case "setVlan": // Push Vlan Tag action pushVlanAction := openflow13.NewActionPushVlan(0x8100) // Set Outer vlan tag field vlanField := openflow13.NewVlanIdField(flowAction.vlanId) setVlanAction := openflow13.NewActionSetField(*vlanField) // Prepend push vlan & setvlan actions to existing instruction actInstr.AddAction(setVlanAction, true) actInstr.AddAction(pushVlanAction, true) addActn = true log.Debugf("flow install. Added pushvlan action: %+v, setVlan actions: %+v", pushVlanAction, setVlanAction) case "popVlan": // Create pop vln action popVlan := openflow13.NewActionPopVlan() // Add it to instruction actInstr.AddAction(popVlan, true) addActn = true log.Debugf("flow install. Added popVlan action: %+v", popVlan) case "setMacDa": // Set Outer MacDA field macDaField := openflow13.NewEthDstField(flowAction.macAddr, nil) setMacDaAction := openflow13.NewActionSetField(*macDaField) // Add set macDa action to the instruction actInstr.AddAction(setMacDaAction, true) addActn = true log.Debugf("flow install. Added setMacDa action: %+v", setMacDaAction) case "setMacSa": // Set Outer MacSA field macSaField := openflow13.NewEthSrcField(flowAction.macAddr, nil) setMacSaAction := openflow13.NewActionSetField(*macSaField) // Add set macDa action to the instruction actInstr.AddAction(setMacSaAction, true) addActn = true log.Debugf("flow install. Added setMacSa Action: %+v", setMacSaAction) case "setTunnelId": // Set tunnelId field tunnelIdField := openflow13.NewTunnelIdField(flowAction.tunnelId) setTunnelAction := openflow13.NewActionSetField(*tunnelIdField) // Add set tunnel action to the instruction actInstr.AddAction(setTunnelAction, true) addActn = true log.Debugf("flow install. Added setTunnelId Action: %+v", setTunnelAction) case "setMetadata": // Set Metadata instruction metadataInstr := openflow13.NewInstrWriteMetadata(flowAction.metadata, flowAction.metadataMask) // Add the instruction to flowmod flowMod.AddInstruction(metadataInstr) default: log.Fatalf("Unknown action type %s", flowAction.actionType) } } // Add the instruction to flow if its not already added if (addActn) && (actInstr != instr) { // Add the instrction to flowmod flowMod.AddInstruction(actInstr) } return nil }
/* * Process incoming ARP packets * ARP request handling in various scenarios: * Src and Dest EP known: * - Proxy ARP if Dest EP is present locally on the host * Src EP known, Dest EP not known: * - ARP Request to a router/VM scenario. Reinject ARP request to VTEPs * Src EP not known, Dest EP known: * - Proxy ARP if Dest EP is present locally on the host * Src and Dest EP not known: * - Ignore processing the request */ func (self *Vxlan) processArp(pkt protocol.Ethernet, inPort uint32) { switch t := pkt.Data.(type) { case *protocol.ARP: log.Debugf("Processing ARP packet on port %d: %+v", inPort, *t) var arpIn protocol.ARP = *t switch arpIn.Operation { case protocol.Type_Request: // If it's a GARP packet, ignore processing if arpIn.IPSrc.String() == arpIn.IPDst.String() { log.Debugf("Ignoring GARP packet") return } if self.agent.portVlanMap[inPort] == nil { log.Debugf("Invalid port vlan mapping. Ignoring arp packet") return } vlan := self.agent.portVlanMap[inPort] // Lookup the Source and Dest IP in the endpoint table srcEp := self.agent.getEndpointByIpVlan(arpIn.IPSrc, *vlan) dstEp := self.agent.getEndpointByIpVlan(arpIn.IPDst, *vlan) // No information about the src or dest EP. Ignore processing. if srcEp == nil && dstEp == nil { log.Debugf("No information on source/destination. Ignoring ARP request.") return } // If we know the dstEp to be present locally, send the Proxy ARP response if dstEp != nil { // Container to Container communication. Send proxy ARP response. // Unknown node to Container communication // -> Send proxy ARP response only if Endpoint is local. // -> This is to avoid sending ARP responses from ofnet agent on multiple hosts if srcEp != nil || (srcEp == nil && dstEp.OriginatorIp.String() == self.agent.localIp.String()) { // Form an ARP response arpPkt, _ := protocol.NewARP(protocol.Type_Reply) arpPkt.HWSrc, _ = net.ParseMAC(dstEp.MacAddrStr) arpPkt.IPSrc = arpIn.IPDst arpPkt.HWDst = arpIn.HWSrc arpPkt.IPDst = arpIn.IPSrc log.Debugf("Sending Proxy ARP response: %+v", arpPkt) // Build the ethernet packet ethPkt := protocol.NewEthernet() ethPkt.VLANID.VID = pkt.VLANID.VID ethPkt.HWDst = arpPkt.HWDst ethPkt.HWSrc = arpPkt.HWSrc ethPkt.Ethertype = 0x0806 ethPkt.Data = arpPkt log.Debugf("Sending Proxy ARP response Ethernet: %+v", ethPkt) // Construct Packet out pktOut := openflow13.NewPacketOut() pktOut.Data = ethPkt pktOut.AddAction(openflow13.NewActionOutput(inPort)) // Send the packet out self.ofSwitch.Send(pktOut) return } } if srcEp != nil && dstEp == nil { // If the ARP request was received from VTEP port // Ignore processing the packet for _, vtepPort := range self.agent.vtepTable { if *vtepPort == inPort { log.Debugf("Received packet from VTEP port. Ignore processing") return } } // ARP request from local container to unknown IP // Reinject ARP to VTEP ports ethPkt := protocol.NewEthernet() ethPkt.HWDst = pkt.HWDst ethPkt.HWSrc = pkt.HWSrc ethPkt.Ethertype = 0x0806 ethPkt.Data = &arpIn log.Infof("Received ARP request for unknown IP: %v. "+ "Reinjecting ARP request Ethernet to VTEP ports: %+v", arpIn.IPDst, ethPkt) // Packet out pktOut := openflow13.NewPacketOut() pktOut.InPort = inPort pktOut.Data = ethPkt tunnelIdField := openflow13.NewTunnelIdField(uint64(srcEp.Vni)) setTunnelAction := openflow13.NewActionSetField(*tunnelIdField) // Add set tunnel action to the instruction pktOut.AddAction(setTunnelAction) for _, vtepPort := range self.agent.vtepTable { log.Debugf("Sending to VTEP port: %+v", *vtepPort) pktOut.AddAction(openflow13.NewActionOutput(*vtepPort)) } // Send the packet out self.ofSwitch.Send(pktOut) } case protocol.Type_Reply: log.Debugf("Received ARP response packet: %+v from port %d", arpIn, inPort) ethPkt := protocol.NewEthernet() ethPkt.VLANID = pkt.VLANID ethPkt.HWDst = pkt.HWDst ethPkt.HWSrc = pkt.HWSrc ethPkt.Ethertype = 0x0806 ethPkt.Data = &arpIn log.Debugf("Sending ARP response Ethernet: %+v", ethPkt) // Packet out pktOut := openflow13.NewPacketOut() pktOut.InPort = inPort pktOut.Data = ethPkt pktOut.AddAction(openflow13.NewActionOutput(openflow13.P_NORMAL)) log.Debugf("Reinjecting ARP reply packet: %+v", pktOut) // Send it out self.ofSwitch.Send(pktOut) } } }
// Install all flow actions func (self *Flow) installFlowActions(flowMod *openflow13.FlowMod, instr openflow13.Instruction) error { var actInstr openflow13.Instruction var addActn bool = false // Create a apply_action instruction to be used if its not already created switch instr.(type) { case *openflow13.InstrActions: actInstr = instr default: actInstr = openflow13.NewInstrApplyActions() } // Loop thru all actions for _, flowAction := range self.flowActions { switch flowAction.actionType { case "pushMpls": //SRTE // Push mpls Tag action pushMplsAction := openflow13.NewActionPushMpls(0x8847) // Set Outer mpls label field mplsLabelField := openflow13.NewMplsLabelField(flowAction.mplsLabel) setMplsAction := openflow13.NewActionSetField(*mplsLabelField) // Prepend push mpls & setlabel actions to existing instruction actInstr.AddAction(setMplsAction, true) actInstr.AddAction(pushMplsAction, true) addActn = true log.Debugf("flow install. Added mpls action: %+v, setMpls actions: %+v", pushMplsAction, setMplsAction) case "popVlanPushMpls": //SRTE // Push mpls Tag action pushMplsAction := openflow13.NewActionPushMpls(0x8847) // Set Outer mpls label field mplsLabelField := openflow13.NewMplsLabelField(flowAction.mplsLabel) setMplsAction := openflow13.NewActionSetField(*mplsLabelField) // Prepend push mpls & setlabel actions to existing instruction actInstr.AddAction(setMplsAction, true) actInstr.AddAction(pushMplsAction, true) // Create pop vlan action popVlan := openflow13.NewActionPopVlan() // Add it to instruction actInstr.AddAction(popVlan, true) addActn = true log.Debugf("flow install. Added pop vlan action: %+v, and Added mpls action: %+v, setMpls actions: %+v", popVlan, pushMplsAction, setMplsAction) case "popMplsPushVlan": //SRTE // Push Vlan Tag action pushVlanAction := openflow13.NewActionPushVlan(0x8100) // Set Outer vlan tag field vlanField := openflow13.NewVlanIdField(flowAction.vlanId, nil) setVlanAction := openflow13.NewActionSetField(*vlanField) // Prepend push vlan & setvlan actions to existing instruction actInstr.AddAction(setVlanAction, true) actInstr.AddAction(pushVlanAction, true) //popmpls action popMplsAction := openflow13.NewActionPopMpls(0x0800) actInstr.AddAction(popMplsAction, true) addActn = true log.Debugf("flow install. Added pop mpls action: %+v, and Added push vlan action: %+v, setVlan actions: %+v", popMplsAction, setVlanAction, vlanField) case "swapMpls": //SRTE - Test this // Set Outer mpls label field mplsLabelField := openflow13.NewMplsLabelField(flowAction.mplsLabel) setMplsAction := openflow13.NewActionSetField(*mplsLabelField) // Prepend push mpls & setlabel actions to existing instruction actInstr.AddAction(setMplsAction, true) addActn = true log.Debugf("flow install. Added swap mpls - setMpls actions: %+v", setMplsAction) case "popMpls": //SRTE // Pop mpls Tag action popMplsAction := openflow13.NewActionPopMpls(0x0800) actInstr.AddAction(popMplsAction, true) addActn = true log.Debugf("flow install. Pop mpls action: %+v", popMplsAction) case "setVlan": // Push Vlan Tag action pushVlanAction := openflow13.NewActionPushVlan(0x8100) // Set Outer vlan tag field vlanField := openflow13.NewVlanIdField(flowAction.vlanId, nil) setVlanAction := openflow13.NewActionSetField(*vlanField) // Prepend push vlan & setvlan actions to existing instruction actInstr.AddAction(setVlanAction, true) actInstr.AddAction(pushVlanAction, true) addActn = true log.Debugf("flow install. Added pushvlan action: %+v, setVlan actions: %+v", pushVlanAction, setVlanAction) case "popVlan": // Create pop vln action popVlan := openflow13.NewActionPopVlan() // Add it to instruction actInstr.AddAction(popVlan, true) addActn = true log.Debugf("flow install. Added popVlan action: %+v", popVlan) case "setMacDa": // Set Outer MacDA field macDaField := openflow13.NewEthDstField(flowAction.macAddr, nil) setMacDaAction := openflow13.NewActionSetField(*macDaField) // Add set macDa action to the instruction actInstr.AddAction(setMacDaAction, true) addActn = true log.Debugf("flow install. Added setMacDa action: %+v", setMacDaAction) case "setMacSa": // Set Outer MacSA field macSaField := openflow13.NewEthSrcField(flowAction.macAddr, nil) setMacSaAction := openflow13.NewActionSetField(*macSaField) // Add set macDa action to the instruction actInstr.AddAction(setMacSaAction, true) addActn = true log.Debugf("flow install. Added setMacSa Action: %+v", setMacSaAction) case "setTunnelId": // Set tunnelId field tunnelIdField := openflow13.NewTunnelIdField(flowAction.tunnelId) setTunnelAction := openflow13.NewActionSetField(*tunnelIdField) // Add set tunnel action to the instruction actInstr.AddAction(setTunnelAction, true) addActn = true log.Debugf("flow install. Added setTunnelId Action: %+v", setTunnelAction) case "setMetadata": // Set Metadata instruction metadataInstr := openflow13.NewInstrWriteMetadata(flowAction.metadata, flowAction.metadataMask) // Add the instruction to flowmod flowMod.AddInstruction(metadataInstr) case "setIPSa": // Set IP src ipSaField := openflow13.NewIpv4SrcField(flowAction.ipAddr, nil) setIPSaAction := openflow13.NewActionSetField(*ipSaField) // Add set action to the instruction actInstr.AddAction(setIPSaAction, true) addActn = true log.Debugf("flow install. Added setIPSa Action: %+v", setIPSaAction) case "setIPDa": // Set IP dst ipDaField := openflow13.NewIpv4DstField(flowAction.ipAddr, nil) setIPDaAction := openflow13.NewActionSetField(*ipDaField) // Add set action to the instruction actInstr.AddAction(setIPDaAction, true) addActn = true log.Debugf("flow install. Added setIPDa Action: %+v", setIPDaAction) case "setTCPSrc": // Set TCP src tcpSrcField := openflow13.NewTcpSrcField(flowAction.l4Port) setTCPSrcAction := openflow13.NewActionSetField(*tcpSrcField) // Add set action to the instruction actInstr.AddAction(setTCPSrcAction, true) addActn = true log.Debugf("flow install. Added setTCPSrc Action: %+v", setTCPSrcAction) case "setTCPDst": // Set TCP dst tcpDstField := openflow13.NewTcpDstField(flowAction.l4Port) setTCPDstAction := openflow13.NewActionSetField(*tcpDstField) // Add set action to the instruction actInstr.AddAction(setTCPDstAction, true) addActn = true log.Debugf("flow install. Added setTCPDst Action: %+v", setTCPDstAction) case "setUDPSrc": // Set UDP src udpSrcField := openflow13.NewUdpSrcField(flowAction.l4Port) setUDPSrcAction := openflow13.NewActionSetField(*udpSrcField) // Add set action to the instruction actInstr.AddAction(setUDPSrcAction, true) addActn = true log.Debugf("flow install. Added setUDPSrc Action: %+v", setUDPSrcAction) case "setUDPDst": // Set UDP dst udpDstField := openflow13.NewUdpDstField(flowAction.l4Port) setUDPDstAction := openflow13.NewActionSetField(*udpDstField) // Add set action to the instruction actInstr.AddAction(setUDPDstAction, true) addActn = true log.Debugf("flow install. Added setUDPDst Action: %+v", setUDPDstAction) default: log.Fatalf("Unknown action type %s", flowAction.actionType) } } // Add the instruction to flow if its not already added if (addActn) && (actInstr != instr) { // Add the instrction to flowmod flowMod.AddInstruction(actInstr) } return nil }