def _add_resolved_route(self, vlan, ip_gw, ip_dst, eth_dst, is_updated=None): ofmsgs = [] if is_updated is not None: in_match = self.valve_in_match( self.fib_table, vlan=vlan, eth_type=self._eth_type(), nw_dst=ip_dst) prefixlen = ipaddr.IPNetwork(ip_dst).prefixlen priority = self.route_priority + prefixlen if is_updated: self.logger.info( 'Updating next hop for route %s via %s (%s)', ip_dst, ip_gw, eth_dst) ofmsgs.extend(self.valve_flowdel( self.fib_table, in_match, priority=priority)) else: self.logger.info( 'Adding new route %s via %s (%s)', ip_dst, ip_gw, eth_dst) if self.use_group_table: inst = [valve_of.apply_actions([valve_of.group_act( group_id=self.ip_gw_to_group_id[ip_gw])])] else: inst = [valve_of.apply_actions(self._nexthop_actions(eth_dst)), valve_of.goto_table(self.eth_dst_table)] ofmsgs.append(self.valve_flowmod( self.fib_table, in_match, priority=priority, inst=inst)) return ofmsgs
def _add_resolved_route(self, vlan, ip_gw, ip_dst, eth_dst, is_updated): ofmsgs = [] if self.routers: in_match = self._route_match(AnyVlan(), ip_dst) else: in_match = self._route_match(vlan, ip_dst) if is_updated: self.logger.info('Updating next hop for route %s via %s (%s)', ip_dst, ip_gw, eth_dst) ofmsgs.extend(self._del_route_flows(vlan, ip_dst)) else: self.logger.info('Adding new route %s via %s (%s)', ip_dst, ip_gw, eth_dst) if self.use_group_table: inst = [ valve_of.apply_actions([ valve_of.group_act(group_id=self.ip_gw_to_group_id[ip_gw]) ]) ] else: inst = [ valve_of.apply_actions(self._nexthop_actions(eth_dst, vlan)), valve_of.goto_table(self.eth_dst_table) ] ofmsgs.append( self.valve_flowmod(self.fib_table, in_match, priority=self._route_priority(ip_dst), inst=inst)) return ofmsgs
def build_flood_rules(self, vlan, modify=False): """Add flows to flood packets to unknown destinations on a VLAN.""" # TODO: not all vendors implement groups well. # That means we need flood rules for each input port, outputting # to all ports except the input port. When all vendors implement # groups correctly we can use them. command = ofp.OFPFC_ADD if modify: command = ofp.OFPFC_MODIFY_STRICT flood_priority = self.flood_priority flood_eth_dst_matches = [] if vlan.unicast_flood: flood_eth_dst_matches.extend([(None, None)]) flood_eth_dst_matches.extend([ ('01:80:C2:00:00:00', 'ff:ff:ff:00:00:00'), # 802.x ('01:00:5E:00:00:00', 'ff:ff:ff:00:00:00'), # IPv4 multicast ('33:33:00:00:00:00', 'ff:ff:00:00:00:00'), # IPv6 multicast (mac.BROADCAST_STR, None), # flood on ethernet broadcasts ]) ofmsgs = [] vlan_all_ports = vlan.flood_ports(vlan.get_ports(), False) mirrored_ports = vlan.mirrored_ports() for eth_dst, eth_dst_mask in flood_eth_dst_matches: for port in vlan_all_ports: if eth_dst is None: flood_acts = self._build_flood_rule_actions( vlan, False, exclude_ports=[port]) else: flood_acts = self._build_flood_rule_actions( vlan, True, exclude_ports=[port]) ofmsgs.append(self.valve_flowmod( self.flood_table, match=self.valve_in_match( self.flood_table, in_port=port.number, vlan=vlan, eth_dst=eth_dst, eth_dst_mask=eth_dst_mask), command=command, inst=[valve_of.apply_actions(flood_acts)], priority=flood_priority)) flood_priority += 1 for port in mirrored_ports: if eth_dst is None: flood_acts = self._build_flood_rule_actions(vlan, False) else: flood_acts = self._build_flood_rule_actions(vlan, True) mirror_acts = [ valve_of.output_port(port.mirror)] + flood_acts ofmsgs.append(self.valve_flowmod( self.flood_table, match=self.valve_in_match( self.flood_table, vlan=vlan, in_port=port.number, eth_dst=eth_dst, eth_dst_mask=eth_dst_mask), command=command, inst=[valve_of.apply_actions(mirror_acts)], priority=flood_priority)) flood_priority += 1 return ofmsgs
def build_acl_entry(rule_conf, acl_allow_inst, port_num=None, vlan_vid=None): acl_inst = [] match_dict = {} for attrib, attrib_value in list(rule_conf.items()): if attrib.startswith('_') and attrib.endswith('_'): continue if attrib == 'in_port': continue if attrib == 'actions': allow = False allow_specified = False if 'allow' in attrib_value: allow_specified = True if attrib_value['allow'] == 1: allow = True if 'mirror' in attrib_value: port_no = attrib_value['mirror'] acl_inst.append( valve_of.apply_actions([valve_of.output_port(port_no)])) if not allow_specified: allow = True if 'output' in attrib_value: output_dict = attrib_value['output'] output_actions = [] output_port = None if 'port' in output_dict: output_port = output_dict['port'] # if destination rewriting selected, rewrite it. if 'dl_dst' in output_dict: output_actions.append( valve_of.set_eth_dst(output_dict['dl_dst'])) # rewrite any VLAN headers. vlan_actions = rewrite_vlan(output_dict) if vlan_actions: output_actions.extend(vlan_actions) # output to a port if specified. if output_port is not None: output_actions.append(valve_of.output_port(output_port)) acl_inst.append(valve_of.apply_actions(output_actions)) # if port specified, output packet now and exit pipeline. if output_port is not None: continue if allow: acl_inst.append(acl_allow_inst) else: match_dict[attrib] = attrib_value if port_num is not None: match_dict['in_port'] = port_num if vlan_vid is not None: match_dict['vlan_vid'] = valve_of.vid_present(vlan_vid) acl_match = valve_of.match_from_dict(match_dict) return acl_match, acl_inst
def add_faucet_vip(self, vlan, faucet_vip): ofmsgs = [] faucet_vip_net = ipaddr.IPNetwork(faucet_vip.exploded) faucet_vip_host = ipaddr.IPNetwork(faucet_vip.ip) max_prefixlen = faucet_vip_host.prefixlen priority = self.route_priority + max_prefixlen ofmsgs.append(self.valve_flowmod( self.eth_src_table, self.valve_in_match( self.eth_src_table, eth_type=self._eth_type(), vlan=vlan, nw_proto=inet.IPPROTO_ICMPV6, ipv6_nd_target=faucet_vip_host, icmpv6_type=icmpv6.ND_NEIGHBOR_SOLICIT), priority=priority, inst=[valve_of.apply_actions([valve_of.output_controller()]), valve_of.goto_table(self.eth_dst_table)])) ofmsgs.append(self.valve_flowmod( self.eth_src_table, self.valve_in_match( self.eth_src_table, eth_type=self._eth_type(), eth_dst=self.faucet_mac, vlan=vlan, nw_proto=inet.IPPROTO_ICMPV6, icmpv6_type=icmpv6.ND_NEIGHBOR_ADVERT), priority=priority, inst=[valve_of.apply_actions([valve_of.output_controller()]), valve_of.goto_table(self.eth_dst_table)])) # Initialize IPv6 FIB ofmsgs.append(self.valve_flowmod( self.eth_src_table, self.valve_in_match( self.eth_src_table, eth_type=self._eth_type(), eth_dst=self.faucet_mac, vlan=vlan), priority=self.route_priority, inst=[valve_of.goto_table(self.fib_table)])) ofmsgs.append(self.valve_flowcontroller( self.fib_table, self.valve_in_match( self.fib_table, eth_type=self._eth_type(), vlan=vlan, nw_proto=inet.IPPROTO_ICMPV6, nw_dst=faucet_vip_host, icmpv6_type=icmpv6.ICMPV6_ECHO_REQUEST), priority=priority)) return ofmsgs
def _add_resolved_route(self, vlan, ip_gw, ip_dst, eth_dst, is_updated=None): ofmsgs = [] if is_updated is not None: in_match = self.valve_in_match( self.fib_table, vlan=vlan, eth_type=self._eth_type(), nw_dst=ip_dst) prefixlen = ipaddr.IPNetwork(ip_dst).prefixlen priority = self.route_priority + prefixlen if is_updated: self.logger.info( 'Updating next hop for route %s via %s (%s)', ip_dst, ip_gw, eth_dst) ofmsgs.extend(self.valve_flowdel( self.fib_table, in_match, priority=priority)) else: self.logger.info( 'Adding new route %s via %s (%s)', ip_dst, ip_gw, eth_dst) ofmsgs.append(self.valve_flowmod( self.fib_table, in_match, priority=priority, inst=[valve_of.apply_actions( [valve_of.set_eth_src(self.faucet_mac), valve_of.set_eth_dst(eth_dst), valve_of.dec_ip_ttl()])] + [valve_of.goto_table(self.eth_dst_table)])) now = time.time() link_neighbor = LinkNeighbor(eth_dst, now) neighbor_cache = self._vlan_neighbor_cache(vlan) neighbor_cache[ip_gw] = link_neighbor return ofmsgs
def _port_add_vlan_tagged(self, port, vlan, forwarding_table, mirror_act): vlan_inst = [ valve_of.goto_table(forwarding_table) ] if mirror_act: vlan_inst = [valve_of.apply_actions(mirror_act)] + vlan_inst return self._port_add_vlan_rules(port, vlan, vlan, vlan_inst)
def _build_group_flood_rules(self, vlan, modify, command): flood_priority = self.flood_priority broadcast_group = self.groups.get_entry( vlan.vid, self._build_group_buckets(vlan, False)) unicast_group = self.groups.get_entry( vlan.vid + valve_of.VLAN_GROUP_OFFSET, self._build_group_buckets(vlan, vlan.unicast_flood)) ofmsgs = [] if modify: ofmsgs.append(broadcast_group.modify()) ofmsgs.append(unicast_group.modify()) else: ofmsgs.extend(broadcast_group.add()) ofmsgs.extend(unicast_group.add()) for unicast_eth_dst, eth_dst, eth_dst_mask in self.FLOOD_DSTS: if unicast_eth_dst and not vlan.unicast_flood: continue group = broadcast_group if not eth_dst: group = unicast_group match = self.flood_table.match(vlan=vlan, eth_dst=eth_dst, eth_dst_mask=eth_dst_mask) ofmsgs.append( self.flood_table.flowmod( match=match, command=command, inst=[ valve_of.apply_actions( [valve_of.group_act(group.group_id)]) ], priority=flood_priority)) flood_priority += 1 return ofmsgs
def build_acl_entry(rule_conf, acl_allow_inst, port_num=None, vlan_vid=None): acl_inst = [] match_dict = {} for attrib, attrib_value in rule_conf.iteritems(): if attrib == 'in_port': continue if attrib == 'actions': allow = False allow_specified = False if 'allow' in attrib_value: allow_specified = True if attrib_value['allow'] == 1: allow = True if 'mirror' in attrib_value: port_no = attrib_value['mirror'] acl_inst.append( valve_of.apply_actions([valve_of.output_port(port_no)])) if not allow_specified: allow = True # if output selected, output packet now and exit pipeline. if 'output' in attrib_value: output_dict = attrib_value['output'] output_actions = [] # if destination rewriting selected, rewrite it. if 'dl_dst' in output_dict: output_actions.append( valve_of.set_eth_dst(output_dict['dl_dst'])) # if vlan tag is specified, push it. if 'vlan_vid' in output_dict: output_actions.extend( valve_of.push_vlan_act(output_dict['vlan_vid'])) # output to port port_no = output_dict['port'] output_actions.append(valve_of.output_port(port_no)) acl_inst.append(valve_of.apply_actions(output_actions)) continue if allow: acl_inst.append(acl_allow_inst) else: match_dict[attrib] = attrib_value if port_num is not None: match_dict['in_port'] = port_num if vlan_vid is not None: match_dict['vlan_vid'] = valve_of.vid_present(vlan_vid) acl_match = valve_of.match_from_dict(match_dict) return acl_match, acl_inst
def _port_add_vlan_untagged(self, port, vlan, forwarding_table, mirror_act): push_vlan_act = mirror_act + valve_of.push_vlan_act(vlan.vid) push_vlan_inst = [ valve_of.apply_actions(push_vlan_act), valve_of.goto_table(forwarding_table) ] null_vlan = namedtuple('null_vlan', 'vid') null_vlan.vid = ofp.OFPVID_NONE return self._port_add_vlan_rules(port, vlan, null_vlan, push_vlan_inst)
def build_flood_rules(self, vlan, modify=False): """Add flows to flood packets to unknown destinations on a VLAN.""" # TODO: not all vendors implement groups well. # That means we need flood rules for each input port, outputting # to all ports except the input port. When all vendors implement # groups correctly we can use them. command = ofp.OFPFC_ADD group_mod_method = valve_of.groupadd if modify: command = ofp.OFPFC_MODIFY_STRICT group_mod_method = valve_of.groupmod flood_priority = self.flood_priority ofmsgs = [] broadcast_buckets = [] unicast_buckets = [] if self.use_group_table and self.stack is None: # Group table usage is not supported for stacking yet # TODO: implement stacking using group table broadcast_buckets = self._build_group_buckets(vlan, False) unicast_buckets = self._build_group_buckets(vlan, vlan.unicast_flood) group_id = vlan.vid ofmsgs.append(group_mod_method( group_id=group_id, buckets=broadcast_buckets)) ofmsgs.append(group_mod_method( group_id=group_id+valve_of.VLAN_GROUP_OFFSET, buckets=unicast_buckets)) for unicast_eth_dst, eth_dst, eth_dst_mask in self.FLOOD_DSTS: if unicast_eth_dst and not vlan.unicast_flood: continue group_id = vlan.vid if not eth_dst: group_id = group_id + valve_of.VLAN_GROUP_OFFSET match = self.valve_in_match( self.flood_table, vlan=vlan, eth_dst=eth_dst, eth_dst_mask=eth_dst_mask) ofmsgs.append(self.valve_flowmod( self.flood_table, match=match, command=command, inst=[valve_of.apply_actions([valve_of.group_act(group_id)])], priority=flood_priority)) flood_priority += 1 else: for unicast_eth_dst, eth_dst, eth_dst_mask in self.FLOOD_DSTS: if unicast_eth_dst and not vlan.unicast_flood: continue ofmsgs.extend(self._build_unmirrored_flood_rules( vlan, eth_dst, eth_dst_mask, unicast_eth_dst, command, flood_priority)) flood_priority += 1 ofmsgs.extend(self._build_mirrored_flood_rules( vlan, eth_dst, eth_dst_mask, unicast_eth_dst, command, flood_priority)) flood_priority += 1 return ofmsgs
def valve_flowcontroller(self, table_id, match=None, priority=None, inst=None): if inst is None: inst = [] return self.valve_flowmod( table_id, match=match, priority=priority, inst=[valve_of.apply_actions( [valve_of.output_controller()])] + inst)
def build_port_out_inst(self, vlan, port): dst_act = [] if not vlan.port_is_tagged(port.number) and port.stack is None: dst_act.append(valve_of.pop_vlan()) dst_act.append(valve_of.output_port(port.number)) if port.mirror is not None: mirror_acts = [valve_of.output_port(port.mirror)] dst_act.extend(mirror_acts) return [valve_of.apply_actions(dst_act)]
def _build_flood_rule_for_port(self, vlan, eth_dst, eth_dst_mask, exclude_unicast, command, flood_priority, port, preflood_acts): ofmsgs = [] match = self.valve_in_match( self.flood_table, vlan=vlan, in_port=port.number, eth_dst=eth_dst, eth_dst_mask=eth_dst_mask) flood_acts = self._build_flood_rule_actions( vlan, exclude_unicast, port) ofmsgs.append(self.valve_flowmod( self.flood_table, match=match, command=command, inst=[valve_of.apply_actions(preflood_acts + flood_acts)], priority=flood_priority)) return ofmsgs
def add_faucet_vip(self, vlan, faucet_vip): ofmsgs = [] max_prefixlen = faucet_vip.ip.max_prefixlen faucet_vip_host = self._host_from_faucet_vip(faucet_vip) priority = self.route_priority + max_prefixlen learn_connected_priority = self.route_priority + faucet_vip.network.prefixlen ofmsgs.append(self.valve_flowmod( self.eth_src_table, self.valve_in_match( self.eth_src_table, eth_type=ether.ETH_TYPE_ARP, nw_dst=faucet_vip_host, vlan=vlan), priority=priority, inst=[valve_of.apply_actions([valve_of.output_controller()])])) # Initialize IPv4 FIB ofmsgs.append(self.valve_flowmod( self.eth_src_table, self.valve_in_match( self.eth_src_table, eth_type=self.ETH_TYPE, eth_dst=self.faucet_mac, vlan=vlan), priority=self.route_priority, inst=[valve_of.goto_table(self.fib_table)])) ofmsgs.append(self.valve_flowcontroller( self.fib_table, self.valve_in_match( self.fib_table, vlan=vlan, eth_type=self.ETH_TYPE, nw_proto=inet.IPPROTO_ICMP, nw_src=faucet_vip, nw_dst=faucet_vip_host), priority=priority)) if self.proactive_learn: ofmsgs.append(self.valve_flowcontroller( self.fib_table, self.valve_in_match( self.fib_table, vlan=vlan, eth_type=self.ETH_TYPE, nw_dst=faucet_vip), priority=learn_connected_priority)) return ofmsgs
def add_faucet_vip(self, vlan, faucet_vip): ofmsgs = [] faucet_vip_net = ipaddr.IPNetwork(faucet_vip.exploded) faucet_vip_host = ipaddr.IPNetwork(faucet_vip.ip) max_prefixlen = faucet_vip_host.prefixlen priority = self.route_priority + max_prefixlen ofmsgs.append(self.valve_flowmod( self.eth_src_table, self.valve_in_match( self.eth_src_table, eth_type=ether.ETH_TYPE_ARP, nw_dst=faucet_vip_host, vlan=vlan), priority=priority, inst=[valve_of.apply_actions([valve_of.output_controller()]), valve_of.goto_table(self.eth_dst_table)])) # Initialize IPv4 FIB ofmsgs.append(self.valve_flowmod( self.eth_src_table, self.valve_in_match( self.eth_src_table, eth_type=self._eth_type(), eth_dst=self.faucet_mac, vlan=vlan), priority=self.route_priority, inst=[valve_of.goto_table(self.fib_table)])) ofmsgs.append(self.valve_flowcontroller( self.fib_table, self.valve_in_match( self.fib_table, vlan=vlan, eth_type=self._eth_type(), nw_proto=inet.IPPROTO_ICMP, nw_src=faucet_vip_net, nw_dst=faucet_vip_host), priority=priority)) return ofmsgs
def add_faucet_vip(self, vlan, faucet_vip): ofmsgs = [] max_prefixlen = faucet_vip.ip.max_prefixlen faucet_vip_host = self._host_from_faucet_vip(faucet_vip) priority = self.route_priority + max_prefixlen learn_connected_priority = self.route_priority + faucet_vip.network.prefixlen faucet_vip_host_nd_mcast = valve_packet.ipv6_link_eth_mcast( valve_packet.ipv6_solicited_node_from_ucast(faucet_vip.ip)) ofmsgs.append( self.valve_flowmod( self.eth_src_table, self.valve_in_match(self.eth_src_table, eth_type=self.ETH_TYPE, vlan=vlan, nw_proto=inet.IPPROTO_ICMPV6, eth_dst=faucet_vip_host_nd_mcast, icmpv6_type=icmpv6.ND_NEIGHBOR_SOLICIT), priority=priority, inst=[ valve_of.apply_actions([valve_of.output_controller()]), valve_of.goto_table(self.flood_table) ])) ofmsgs.append( self.valve_flowmod( self.eth_src_table, self.valve_in_match(self.eth_src_table, eth_type=self.ETH_TYPE, eth_dst=self.faucet_mac, vlan=vlan, nw_proto=inet.IPPROTO_ICMPV6, icmpv6_type=icmpv6.ND_NEIGHBOR_ADVERT), priority=priority, inst=[valve_of.apply_actions([valve_of.output_controller()])])) if faucet_vip.ip in valve_packet.IPV6_LINK_LOCAL: ofmsgs.append( self.valve_flowmod( self.eth_src_table, self.valve_in_match( self.eth_src_table, eth_type=self.ETH_TYPE, vlan=vlan, nw_proto=inet.IPPROTO_ICMPV6, eth_dst=valve_packet.IPV6_ALL_ROUTERS_MCAST, icmpv6_type=icmpv6.ND_ROUTER_SOLICIT), priority=priority, inst=[ valve_of.apply_actions([valve_of.output_controller()]), valve_of.goto_table(self.flood_table) ])) # Initialize IPv6 FIB ofmsgs.append( self.valve_flowmod(self.eth_src_table, self.valve_in_match(self.eth_src_table, eth_type=self.ETH_TYPE, eth_dst=self.faucet_mac, vlan=vlan), priority=self.route_priority, inst=[valve_of.goto_table(self.fib_table)])) ofmsgs.append( self.valve_flowcontroller( self.fib_table, self.valve_in_match(self.fib_table, eth_type=self.ETH_TYPE, vlan=vlan, nw_proto=inet.IPPROTO_ICMPV6, nw_dst=faucet_vip_host, icmpv6_type=icmpv6.ICMPV6_ECHO_REQUEST), priority=priority, max_len=128)) if self.proactive_learn: ofmsgs.append( self.valve_flowcontroller(self.fib_table, self.valve_in_match( self.fib_table, vlan=vlan, eth_type=self.ETH_TYPE, nw_dst=faucet_vip), priority=learn_connected_priority)) return ofmsgs