def _make_bum_match(self, metadata): match = self.parser.OFPMatch() match.set_metadata(metadata) encoded_mac = mac_api.haddr_to_bin(mac_api.DONTCARE_STR) encoded_mask = mac_api.haddr_to_bin(mac_api.UNICAST) match.set_dl_dst_masked(encoded_mac, encoded_mask) return match
def to_actions(dp, acts): actions = [] for a in acts: action_type = a.get('type') if action_type == 'OUTPUT': port = UTIL.ofp_port_from_user( a.get('port', ofproto_v1_0.OFPP_NONE)) # NOTE: The reason of this magic number (0xffe5) # is because there is no good constant in of1.0. # The same value as OFPCML_MAX of of1.2 and of1.3 is used. max_len = str_to_int(a.get('max_len', 0xffe5)) actions.append(dp.ofproto_parser.OFPActionOutput(port, max_len)) elif action_type == 'SET_VLAN_VID': vlan_vid = str_to_int(a.get('vlan_vid', 0xffff)) actions.append(dp.ofproto_parser.OFPActionVlanVid(vlan_vid)) elif action_type == 'SET_VLAN_PCP': vlan_pcp = str_to_int(a.get('vlan_pcp', 0)) actions.append(dp.ofproto_parser.OFPActionVlanPcp(vlan_pcp)) elif action_type == 'STRIP_VLAN': actions.append(dp.ofproto_parser.OFPActionStripVlan()) elif action_type == 'SET_DL_SRC': dl_src = haddr_to_bin(a.get('dl_src')) actions.append(dp.ofproto_parser.OFPActionSetDlSrc(dl_src)) elif action_type == 'SET_DL_DST': dl_dst = haddr_to_bin(a.get('dl_dst')) actions.append(dp.ofproto_parser.OFPActionSetDlDst(dl_dst)) elif action_type == 'SET_NW_SRC': nw_src = ipv4_to_int(a.get('nw_src')) actions.append(dp.ofproto_parser.OFPActionSetNwSrc(nw_src)) elif action_type == 'SET_NW_DST': nw_dst = ipv4_to_int(a.get('nw_dst')) actions.append(dp.ofproto_parser.OFPActionSetNwDst(nw_dst)) elif action_type == 'SET_NW_TOS': nw_tos = str_to_int(a.get('nw_tos', 0)) actions.append(dp.ofproto_parser.OFPActionSetNwTos(nw_tos)) elif action_type == 'SET_TP_SRC': tp_src = str_to_int(a.get('tp_src', 0)) actions.append(dp.ofproto_parser.OFPActionSetTpSrc(tp_src)) elif action_type == 'SET_TP_DST': tp_dst = str_to_int(a.get('tp_dst', 0)) actions.append(dp.ofproto_parser.OFPActionSetTpDst(tp_dst)) elif action_type == 'ENQUEUE': port = UTIL.ofp_port_from_user( a.get('port', ofproto_v1_0.OFPP_NONE)) queue_id = UTIL.ofp_queue_from_user(a.get('queue_id', 0)) actions.append(dp.ofproto_parser.OFPActionEnqueue(port, queue_id)) else: LOG.error('Unknown action type') return actions
def _add_local_port_dispatch(self, lport): lport_id = lport.id mac = lport.mac port_key = lport.unique_key network_id = lport.lswitch.unique_key topic = lport.topic parser = self.parser ofproto = self.ofproto # Go to dispatch table according to unique metadata & mac match = parser.OFPMatch() match.set_metadata(network_id) match.set_dl_dst(haddr_to_bin(mac)) actions = [parser.OFPActionSetField(reg7=port_key)] action_inst = parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions) goto_inst = parser.OFPInstructionGotoTable( const.INGRESS_CONNTRACK_TABLE) inst = [action_inst, goto_inst] self.mod_flow(inst=inst, table_id=const.INGRESS_DESTINATION_PORT_LOOKUP_TABLE, priority=const.PRIORITY_HIGH, match=match) # Egress classifier for port match = parser.OFPMatch(reg7=port_key) inst = [parser.OFPInstructionGotoTable(const.INGRESS_CONNTRACK_TABLE)] self.mod_flow(inst=inst, table_id=const.EGRESS_TABLE, priority=const.PRIORITY_MEDIUM, match=match) self._add_multicast_broadcast_handling_for_local_port( lport_id, port_key, network_id, topic)
def add_flow(self, datapath, in_port, dst, src, actions): ofproto = datapath.ofproto match = datapath.ofproto_parser.OFPMatch(in_port=in_port, dl_dst=haddr_to_bin(dst), dl_src=haddr_to_bin(src)) mod = datapath.ofproto_parser.OFPFlowMod( datapath=datapath, match=match, cookie=0, command=ofproto.OFPFC_ADD, idle_timeout=0, hard_timeout=0, priority=ofproto.OFP_DEFAULT_PRIORITY, flags=ofproto.OFPFF_SEND_FLOW_REM, actions=actions) datapath.send_msg(mod)
def _delete_dst_classifier_flow_for_port(self, network_id, mac): parser = self.parser ofproto = self.ofproto match = parser.OFPMatch() match.set_metadata(network_id) match.set_dl_dst(haddr_to_bin(mac)) self.mod_flow(table_id=const.L2_LOOKUP_TABLE, command=ofproto.OFPFC_DELETE, priority=const.PRIORITY_MEDIUM, match=match)
def mac_addr_all_zeros(mac_addr): """Returns True if mac_addr is all zeros. Args: mac_addr (str): MAC address. Returns: bool: True if all zeros. """ mac_bin = haddr_to_bin(mac_addr) return mac_bin == DONTCARE
def mac_addr_is_unicast(mac_addr): """Returns True if mac_addr is a unicast Ethernet address. Args: mac_addr (str): MAC address. Returns: bool: True if a unicast Ethernet address. """ mac_bin = haddr_to_bin(mac_addr) if mac_bin == BROADCAST: return False return not is_multicast(mac_bin)
def _delete_router_port(self, router, router_port): """ Handle the removal of a router interface from a router. Undoes the actions in #_add_new_router_port. :param router: The router on which the interface is removed :type router: LogicalRouter model object :param router_port: The router interface being removed :type router_port: RouterInterface model object """ LOG.info("Removing logical router interface = %s", router_port) local_network_id = router_port.lswitch.unique_key parser = self.parser ofproto = self.ofproto router_unique_key = router.unique_key ip = router_port.network.ip mac = router_port.mac # Delete rule for making packets go from L2_LOOKUP_TABLE # to L3_LOOKUP_TABLE match = parser.OFPMatch() match.set_metadata(local_network_id) match.set_dl_dst(os_ken_mac_lib.haddr_to_bin(mac)) self.mod_flow( table_id=const.L2_LOOKUP_TABLE, command=ofproto.OFPFC_DELETE, priority=const.PRIORITY_HIGH, match=match) # Delete ARP & ICMP responder for router interface if ip.version == common_const.IP_VERSION_4: arp_responder.ArpResponder(self, local_network_id, ip).remove() icmp_responder.ICMPResponder(self, ip, router_key=router_unique_key).remove() # Delete rule for packets whose destination is router interface. match = self._get_router_interface_match(router_unique_key, ip) self.mod_flow( table_id=const.L3_LOOKUP_TABLE, command=ofproto.OFPFC_DELETE, priority=const.PRIORITY_HIGH, match=match) # Delete rule for routing packets to subnet of this router port match = self._get_router_route_match(router_unique_key, router_port.network) self.mod_flow( table_id=const.L3_LOOKUP_TABLE, command=ofproto.OFPFC_DELETE, priority=const.PRIORITY_MEDIUM, match=match)
def _add_dst_classifier_flow_for_port(self, network_id, mac, port_key): parser = self.parser ofproto = self.ofproto match = parser.OFPMatch() match.set_metadata(network_id) match.set_dl_dst(haddr_to_bin(mac)) actions = [parser.OFPActionSetField(reg7=port_key)] action_inst = parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions) goto_inst = parser.OFPInstructionGotoTable(const.EGRESS_TABLE) inst = [action_inst, goto_inst] self.mod_flow(inst=inst, table_id=const.L2_LOOKUP_TABLE, priority=const.PRIORITY_MEDIUM, match=match)
def _remove_local_port_pipeline_interface(self, lport): parser = self.parser ofproto = self.ofproto local_network_id = lport.lswitch.unique_key # Remove egress classifier for port match = parser.OFPMatch(reg7=lport.unique_key) self.mod_flow(table_id=const.EGRESS_TABLE, command=ofproto.OFPFC_DELETE, priority=const.PRIORITY_MEDIUM, match=match) # Remove ingress destination lookup for port match = parser.OFPMatch() match.set_metadata(local_network_id) match.set_dl_dst(haddr_to_bin(lport.mac)) self.mod_flow(table_id=const.INGRESS_DESTINATION_PORT_LOOKUP_TABLE, command=ofproto.OFPFC_DELETE, priority=const.PRIORITY_HIGH, match=match) # Update multicast and broadcast self._del_multicast_broadcast_handling_for_local( lport.id, lport.topic, local_network_id)
def _get_multicast_broadcast_match(self, network_id): match = self.parser.OFPMatch(eth_dst='01:00:00:00:00:00') addint = haddr_to_bin('01:00:00:00:00:00') match.set_dl_dst_masked(addint, addint) match.set_metadata(network_id) return match
def to_match(dp, attrs): ofp = dp.ofproto wildcards = ofp.OFPFW_ALL in_port = 0 dl_src = 0 dl_dst = 0 dl_vlan = 0 dl_vlan_pcp = 0 dl_type = 0 nw_tos = 0 nw_proto = 0 nw_src = 0 nw_dst = 0 tp_src = 0 tp_dst = 0 for key, value in attrs.items(): if key == 'in_port': in_port = UTIL.ofp_port_from_user(value) wildcards &= ~ofp.OFPFW_IN_PORT elif key == 'dl_src': dl_src = haddr_to_bin(value) wildcards &= ~ofp.OFPFW_DL_SRC elif key == 'dl_dst': dl_dst = haddr_to_bin(value) wildcards &= ~ofp.OFPFW_DL_DST elif key == 'dl_vlan': dl_vlan = str_to_int(value) wildcards &= ~ofp.OFPFW_DL_VLAN elif key == 'dl_vlan_pcp': dl_vlan_pcp = str_to_int(value) wildcards &= ~ofp.OFPFW_DL_VLAN_PCP elif key == 'dl_type': dl_type = str_to_int(value) wildcards &= ~ofp.OFPFW_DL_TYPE elif key == 'nw_tos': nw_tos = str_to_int(value) wildcards &= ~ofp.OFPFW_NW_TOS elif key == 'nw_proto': nw_proto = str_to_int(value) wildcards &= ~ofp.OFPFW_NW_PROTO elif key == 'nw_src': ip = value.split('/') nw_src = struct.unpack('!I', socket.inet_aton(ip[0]))[0] mask = 32 if len(ip) == 2: mask = int(ip[1]) assert 0 < mask <= 32 v = (32 - mask) << ofp.OFPFW_NW_SRC_SHIFT | \ ~ofp.OFPFW_NW_SRC_MASK wildcards &= v elif key == 'nw_dst': ip = value.split('/') nw_dst = struct.unpack('!I', socket.inet_aton(ip[0]))[0] mask = 32 if len(ip) == 2: mask = int(ip[1]) assert 0 < mask <= 32 v = (32 - mask) << ofp.OFPFW_NW_DST_SHIFT | \ ~ofp.OFPFW_NW_DST_MASK wildcards &= v elif key == 'tp_src': tp_src = str_to_int(value) wildcards &= ~ofp.OFPFW_TP_SRC elif key == 'tp_dst': tp_dst = str_to_int(value) wildcards &= ~ofp.OFPFW_TP_DST else: LOG.error("unknown match name %s, %s, %d", key, value, len(key)) match = dp.ofproto_parser.OFPMatch( wildcards, in_port, dl_src, dl_dst, dl_vlan, dl_vlan_pcp, dl_type, nw_tos, nw_proto, nw_src, nw_dst, tp_src, tp_dst) return match
def _make_bum_match(self, **kwargs): match = self.parser.OFPMatch(**kwargs) bum_addr = mac_api.haddr_to_bin(mac_api.UNICAST) match.set_dl_dst_masked(bum_addr, bum_addr) return match
def haddr_to_bin(self, string): return mac.haddr_to_bin(string)
class RunTestMininet(app_manager.OSKenApp): _CONTEXTS = {'dpset': dpset.DPSet} OFP_VERSIONS = [ofproto_v1_2.OFP_VERSION] ZERO_MAC = mac.haddr_to_bin('00:00:00:00:00:00') BROADCAST_MAC = mac.haddr_to_bin('ff:ff:ff:ff:ff:ff') OSKEN_MAC = mac.haddr_to_bin('fe:ee:ee:ee:ee:ef') HOST_MAC = mac.haddr_to_bin('00:00:00:00:00:01') OSKEN_IP = int(netaddr.IPAddress('10.0.0.100')) HOST_IP = int(netaddr.IPAddress('10.0.0.1')) def __init__(self, *args, **kwargs): super(RunTestMininet, self).__init__(*args, **kwargs) def _send_msg(self, dp, data): buffer_id = 0xffffffff in_port = dp.ofproto.OFPP_LOCAL actions = [dp.ofproto_parser.OFPActionOutput(1, 0)] msg = dp.ofproto_parser.OFPPacketOut(dp, buffer_id, in_port, actions, data) dp.send_msg(msg) def _add_flow(self, dp, match, actions): inst = [ dp.ofproto_parser.OFPInstructionActions( dp.ofproto.OFPIT_APPLY_ACTIONS, actions) ] mod = dp.ofproto_parser.OFPFlowMod(dp, cookie=0, cookie_mask=0, table_id=0, command=dp.ofproto.OFPFC_ADD, idle_timeout=0, hard_timeout=0, priority=0xff, buffer_id=0xffffffff, out_port=dp.ofproto.OFPP_ANY, out_group=dp.ofproto.OFPG_ANY, flags=0, match=match, instructions=inst) dp.send_msg(mod) def _find_protocol(self, pkt, name): for p in pkt.protocols: if hasattr(p, 'protocol_name'): if p.protocol_name == name: return p def _get_protocols(self, pkt): protocols = {} for p in pkt: if hasattr(p, 'protocol_name'): protocols[p.protocol_name] = p else: protocols['payload'] = p return protocols def _build_ether(self, ethertype, dst_mac=HOST_MAC): e = ethernet.ethernet(dst_mac, self.OSKEN_MAC, ethertype) return e def _build_arp(self, opcode, dst_ip=HOST_IP): if opcode == arp.ARP_REQUEST: _eth_dst_mac = self.BROADCAST_MAC _arp_dst_mac = self.ZERO_MAC elif opcode == arp.ARP_REPLY: _eth_dst_mac = self.HOST_MAC _arp_dst_mac = self.HOST_MAC e = self._build_ether(ether.ETH_TYPE_ARP, _eth_dst_mac) a = arp.arp(hwtype=1, proto=ether.ETH_TYPE_IP, hlen=6, plen=4, opcode=opcode, src_mac=self.OSKEN_MAC, src_ip=self.OSKEN_IP, dst_mac=_arp_dst_mac, dst_ip=dst_ip) p = packet.Packet() p.add_protocol(e) p.add_protocol(a) p.serialize() return p def _build_echo(self, _type, echo): e = self._build_ether(ether.ETH_TYPE_IP) ip = ipv4.ipv4(version=4, header_length=5, tos=0, total_length=84, identification=0, flags=0, offset=0, ttl=64, proto=inet.IPPROTO_ICMP, csum=0, src=self.OSKEN_IP, dst=self.HOST_IP) ping = icmp.icmp(_type, code=0, csum=0, data=echo) p = packet.Packet() p.add_protocol(e) p.add_protocol(ip) p.add_protocol(ping) p.serialize() return p def _garp(self): p = self._build_arp(arp.ARP_REQUEST, self.OSKEN_IP) return p.data def _arp_request(self): p = self._build_arp(arp.ARP_REQUEST, self.HOST_IP) return p.data def _arp_reply(self): p = self._build_arp(arp.ARP_REPLY, self.HOST_IP) return p.data def _echo_request(self, echo): p = self._build_echo(icmp.ICMP_ECHO_REQUEST, echo) return p.data def _echo_reply(self, echo): p = self._build_echo(icmp.ICMP_ECHO_REPLY, echo) return p.data @handler.set_ev_cls(ofp_event.EventOFPPacketIn, handler.MAIN_DISPATCHER) def packet_in_handler(self, ev): msg = ev.msg dp = msg.datapath pkt = packet.Packet(array.array('B', msg.data)) p_arp = self._find_protocol(pkt, "arp") p_icmp = self._find_protocol(pkt, "icmp") p_ipv4 = self._find_protocol(pkt, "ipv4") if p_arp: src_ip = str(netaddr.IPAddress(p_arp.src_ip)) dst_ip = str(netaddr.IPAddress(p_arp.dst_ip)) if p_arp.opcode == arp.ARP_REQUEST: LOG.debug("--- PacketIn: ARP_Request: %s->%s", src_ip, dst_ip) if p_arp.dst_ip == self.OSKEN_IP: LOG.debug("--- send Pkt: ARP_Reply") data = self._arp_reply() self._send_msg(dp, data) elif p_arp.dst_ip == self.HOST_IP: LOG.debug(" PacketIn: GARP") LOG.debug("--- send Pkt: ARP_Request") data = self._arp_request() self._send_msg(dp, data) elif p_arp.opcode == arp.ARP_REPLY: LOG.debug("--- PacketIn: ARP_Reply: %s->%s", src_ip, dst_ip) LOG.debug("--- send Pkt: Echo_Request") echo = icmp.echo(id_=66, seq=1) data = self._echo_request(echo) self._send_msg(dp, data) if p_icmp: src = str(netaddr.IPAddress(p_ipv4.src)) dst = str(netaddr.IPAddress(p_ipv4.dst)) if p_icmp.type == icmp.ICMP_ECHO_REQUEST: LOG.debug("--- PacketIn: Echo_Request: %s->%s", src, dst) if p_ipv4.dst == self.OSKEN_IP: LOG.debug("--- send Pkt: Echo_Reply") echo = p_icmp.data echo.data = bytearray(echo.data) data = self._echo_reply(echo) self._send_msg(dp, data) elif p_icmp.type == icmp.ICMP_ECHO_REPLY: LOG.debug("--- PacketIn: Echo_Reply: %s->%s", src, dst) @handler.set_ev_cls(dpset.EventDP, dpset.DPSET_EV_DISPATCHER) def handler_datapath(self, ev): if ev.enter: dp = ev.dp LOG.debug("--- send Pkt: Gratuitous ARP_Request") data = self._garp() self._send_msg(dp, data)
def _add_new_router_port(self, router, router_port): """ Handle the creation of a new router interface on the router. * Match L2 address and update reg5 * Install ARP and ICMP responders * Match packets with router as dst * Add flows for new route entries :param router: The router on which the interface is added :type router: LogicalRouter model object :param router_port: The router interface being added :type router_port: RouterInterface model object """ LOG.info("Adding new logical router interface = %r", router_port) local_network_id = router_port.lswitch.unique_key parser = self.parser ofproto = self.ofproto mac = router_port.mac router_unique_key = router.unique_key dst_ip = router_port.network.ip is_ipv4 = (netaddr.IPAddress(dst_ip).version == common_const.IP_VERSION_4) # Add rule for making packets go from L2_LOOKUP_TABLE # to L3_LOOKUP_TABLE match = parser.OFPMatch() match.set_metadata(local_network_id) match.set_dl_dst(os_ken_mac_lib.haddr_to_bin(mac)) actions = [parser.OFPActionSetField(reg5=router_unique_key)] action_inst = parser.OFPInstructionActions( ofproto.OFPIT_APPLY_ACTIONS, actions) goto_inst = parser.OFPInstructionGotoTable(const.L3_LOOKUP_TABLE) inst = [action_inst, goto_inst] self.mod_flow( inst=inst, table_id=const.L2_LOOKUP_TABLE, priority=const.PRIORITY_HIGH, match=match) # Add router ARP & ICMP responder for IPv4 Addresses if is_ipv4: arp_responder.ArpResponder(self, local_network_id, dst_ip, mac).add() icmp_responder.ICMPResponder(self, dst_ip, router_key=router_unique_key).add() # If router interface is not concrete, send to local controller. local # controller will create icmp unreachable message. A virtual router # interface will not be in local cache, as it doesn't have chassis # information. lport = self.db_store.get_one(l2.LogicalPort(id=router_port.id)) if not lport: match = self._get_router_interface_match(router_unique_key, dst_ip) actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, ofproto.OFPCML_NO_BUFFER)] action_inst = parser.OFPInstructionActions( ofproto.OFPIT_APPLY_ACTIONS, actions) self.mod_flow( inst=[action_inst], table_id=const.L3_LOOKUP_TABLE, priority=const.PRIORITY_HIGH, match=match) else: self._add_concrete_router_interface(lport, router=router) # Add rule for routing packets to subnet of this router port match = self._get_router_route_match(router_unique_key, router_port.network) self._add_subnet_send_to_route(match, local_network_id, router_port)