class GSS(object): def __init__(self, logger, sender, config): self.logger = logger self.sender = sender self.config = config self.fm_builder = FlowModMsgBuilder(0, self.config.flanc_auth["key"]) self.vmac_builder = VMACBuilder(self.config.vmac_options) def handle_BGP(self, rule_type): ### BGP traffic to route server port = self.config.route_server.ports[0] self.logger.debug("JEROENDEBUG-----------" + str(port)) action = {"fwd": [port.id]} match = {"eth_dst": port.mac, "tcp_src": BGP} self.fm_builder.add_flow_mod("insert", rule_type, BGP_PRIORITY, match, action) match = {"eth_dst": port.mac, "tcp_dst": BGP} self.fm_builder.add_flow_mod("insert", rule_type, BGP_PRIORITY, match, action) ### BGP traffic to participants for participant in self.config.peers.values(): for port in participant.ports: match = {"eth_dst": port.mac, "tcp_src": BGP} action = {"fwd": [port.id]} self.fm_builder.add_flow_mod("insert", rule_type, BGP_PRIORITY, match, action) match = {"eth_dst": port.mac, "tcp_dst": BGP} self.fm_builder.add_flow_mod("insert", rule_type, BGP_PRIORITY, match, action) def handle_ARP_in_main(self, rule_type): ### direct all ARP responses for the route server to it port = self.config.route_server.ports[0] match = {"eth_type": ETH_TYPE_ARP, "eth_dst": port.mac} action = {"fwd": [port.id]} self.fm_builder.add_flow_mod("insert", rule_type, ARP_PRIORITY, match, action) for participant in self.config.peers.values(): ### make sure ARP replies reach the participants for port in participant.ports: match = {"eth_type": ETH_TYPE_ARP, "eth_dst": port.mac} action = {"fwd": [port.id]} self.fm_builder.add_flow_mod("insert", rule_type, ARP_PRIORITY, match, action) ### direct gratuituous ARPs only to the respective participant i = 0 for port in participant.ports: vmac = self.vmac_builder.part_port_match(participant.name, i, inbound_bit = False) vmac_mask = self.vmac_builder.part_port_mask(False) match = {"in_port": "arp", "eth_type": ETH_TYPE_ARP, "eth_dst": (vmac, vmac_mask)} action = {"set_eth_dst": MAC_BROADCAST, "fwd": [port.id]} self.fm_builder.add_flow_mod("insert", rule_type, ARP_PRIORITY, match, action) i += 1 ### flood ARP requests that have gone through the arp switch, but only on non switch-switch ports match = {"in_port": "arp", "eth_type": ETH_TYPE_ARP, "eth_dst": MAC_BROADCAST} ports = [] for participant in self.config.peers.values(): for port in participant.ports: ports.append(port.id) ports.append(self.config.route_server.ports[0].id) action = {"fwd": ports} self.fm_builder.add_flow_mod("insert", rule_type, ARP_BROADCAST_PRIORITY, match, action) ### forward all ARP requests to the arp switch match = {"eth_type": ETH_TYPE_ARP} action = {"fwd": ["arp"]} self.fm_builder.add_flow_mod("insert", rule_type, VNH_ARP_FILTER_PRIORITY, match, action) def handle_ARP_in_arp(self, rule_type): ### direct ARP requests for VNHs to ARP proxy port = self.config.arp_proxy.ports[0] match = {"in_port": "main", "eth_type": ETH_TYPE_ARP, "arp_tpa": (str(self.config.vnhs.network), str(self.config.vnhs.netmask))} action = {"fwd": [port.id]} self.fm_builder.add_flow_mod("insert", rule_type, VNH_ARP_PRIORITY, match, action) ### send all other ARP requests back match = {"eth_type": ETH_TYPE_ARP, "in_port": "main"} action = {"fwd": [OFPP_IN_PORT]} self.fm_builder.add_flow_mod("insert", rule_type, DEFAULT_PRIORITY, match, action) ### send all ARP replies from the ARP proxy to the main switch match = {"eth_type": ETH_TYPE_ARP, "in_port": "arp proxy"} action = {"fwd": ["main"]} self.fm_builder.add_flow_mod("insert", rule_type, DEFAULT_PRIORITY, match, action) def handle_participant_with_outbound(self, rule_type): for participant in self.config.peers.values(): ### outbound policies specified if participant.outbound_rules: mac = None for port in participant.ports: if mac is None: mac = port.mac match = {"in_port": port.id} action = {"set_eth_src": mac, "fwd": ["outbound"]} self.fm_builder.add_flow_mod("insert", rule_type, OUTBOUND_PRIORITY, match, action) def handle_participant_with_inbound(self, rule_type, mask_inbound_bit): for participant in self.config.peers.values(): ### inbound policies specified if participant.inbound_rules: i = 0 for port in participant.ports: vmac = self.vmac_builder.part_port_match(participant.name, i, False) i += 1 vmac_mask = self.vmac_builder.part_port_mask(mask_inbound_bit) match = {"eth_dst": (vmac, vmac_mask)} action = {"set_eth_dst": port.mac, "fwd": [port.id]} self.fm_builder.add_flow_mod("insert", rule_type, FORWARDING_PRIORITY, match, action) def default_forwarding(self, rule_type): for participant in self.config.peers.values(): ### default forwarding if not participant.inbound_rules: vmac = self.vmac_builder.next_hop_match(participant.name, False) vmac_mask = self.vmac_builder.next_hop_mask(False) port = participant.ports[0] match = {"eth_dst": (vmac, vmac_mask)} action = {"set_eth_dst": port.mac, "fwd": [port.id]} self.fm_builder.add_flow_mod("insert", rule_type, FORWARDING_PRIORITY, match, action) def default_forwarding_inbound(self, rule_type, fwd): ## set the inbound bit to zero for participant in self.config.peers.values(): if participant.inbound_rules: port = participant.ports[0] vmac_match = self.vmac_builder.next_hop_match(participant.name, False) vmac_match_mask = self.vmac_builder.next_hop_mask(False) vmac_action = self.vmac_builder.part_port_match(participant.name, 0, False) match = {"eth_dst": (vmac_match, vmac_match_mask)} action = {"set_eth_dst": vmac_action, "fwd": [fwd]} self.fm_builder.add_flow_mod("insert", "inbound", INBOUND_PRIORITY, match, action) def handle_inbound(self, rule_type): vmac = self.vmac_builder.only_first_bit() match = {"eth_dst": (vmac, vmac)} action = {"fwd": ["outbound"]} self.fm_builder.add_flow_mod("insert", rule_type, INBOUND_BIT_PRIORITY, match, action) def match_any_fwd(self, rule_type, dst): match = {} action = {"fwd": [dst]} self.fm_builder.add_flow_mod("insert", rule_type, DEFAULT_PRIORITY, match, action) def delete_flow_rule(self, rule_type, cookie, cookie_mask): self.fm_builder.delete_flow_mod("remove", rule_type, cookie, cookie_mask) def start(self): self.logger.info('start') self.init_fabric() self.sender.send(self.fm_builder.get_msg()) self.logger.info('sent flow mods to reference monitor')
class PCtrl(object): def __init__(self, id, config, logger): # participant id self.id = id # print ID for logging self.logger = logger # used to signal termination self.run = True self.prefix_lock = {} self.arp_table = {} # Initialize participant params self.cfg = PConfig(config, self.id) # Vmac encoding mode # self.cfg.vmac_mode = config_file["vmac_mode"] # Dataplane mode---multi table or multi switch # self.cfg.dp_mode = config_file["dp_mode"] self.policies = self.cfg.config["Policies"] # The port 0 MAC is used for tagging outbound rules as belonging to us self.port0_mac = self.cfg.port0_mac self.nexthop_2_part = self.cfg.config["Next Hops"] # VNHs related params self.num_VNHs_in_use = 0 self.VNH_2_prefix = {} self.prefix_2_VNH = {} # Keeps track of the current participant that is the default next hop for VNHs self.nhpart_2_VNHs = {} # Superset related params if self.cfg.isSupersetsMode(): self.supersets = SuperSets(self, self.cfg.vmac_options) else: # TODO: create similar class and variables for MDS self.mds = None # Keep track of flow rules pushed self.dp_pushed = [] # Keep track of flow rules which are scheduled to be pushed self.dp_queued = [] self.bgp_instance = BGPPeer(id, self.cfg.asn, self.cfg.ports, self.cfg.peers_in, self.cfg.peers_out) self.fm_builder = FlowModMsgBuilder(self.id) def sanitize_policies(self, policies): port_count = len(self.cfg.ports) # sanitize the input policies if 'inbound' in policies: for policy in policies['inbound']: if 'action' not in policy: continue if 'fwd' in policy['action'] and int( policy['action']['fwd']) >= port_count: policy['action']['fwd'] = 0 return policies def load_policies(self, policy_file): # Load policies from file with open(policy_file, 'r') as f: policies = json.load(f) return self.sanitize_policies(policies) def initialize_dataplane(self): "Read the config file and update the queued policy variable" self.logger.info("Initializing inbound rules") final_switch = "main-in" if self.cfg.isMultiTableMode() or self.cfg.isMultiHopMode(): final_switch = "main-out" self.init_vnh_assignment() rule_msgs = init_inbound_rules(self.id, self.policies, self.supersets, final_switch) self.logger.debug("Rule Messages INBOUND:: " + str(rule_msgs)) rule_msgs2 = init_outbound_rules(self, self.id, self.policies, self.supersets, final_switch) self.logger.debug("Rule Messages OUTBOUND:: " + str(rule_msgs2)) if 'changes' in rule_msgs2: if 'changes' not in rule_msgs: rule_msgs['changes'] = [] rule_msgs['changes'] += rule_msgs2['changes'] #TODO: Initialize Outbound Policies from RIB self.logger.debug("Rule Messages:: " + str(rule_msgs)) if 'changes' in rule_msgs: self.dp_queued.extend(rule_msgs["changes"]) def push_dp(self): ''' (1) Check if there are any policies queued to be pushed (2) Send the queued policies to reference monitor ''' # it is crucial that dp_queued is traversed chronologically for flowmod in self.dp_queued: self.fm_builder.add_flow_mod(**flowmod) self.dp_pushed.append(flowmod) # reset queue self.dp_queued = [] flows = self.fm_builder.get_msg() self.fm_builder.reset_flow_mod() return flows # reset flow_mods after send - self.flow_mods = [] def process_event(self, data, mod_type=None): "Locally process each incoming network event" if 'bgp' in data: self.logger.debug("Event Received: BGP Update.") route = data['bgp'] # Process the incoming BGP updates from XRS #self.logger.debug("BGP Route received: "+str(route)+" "+str(type(route))) return self.process_bgp_route(route) elif 'policy' in data: # Process the event requesting change of participants' policies self.logger.debug("Event Received: Policy change.") change_info = data['policy'] for element in change_info: if 'remove' in element: self.process_policy_changes(element['remove'], 'remove') #self.logger.debug("PART_Test: REMOVE: %s" % element) if 'insert' in element: self.process_policy_changes(element['insert'], 'insert') #self.logger.debug("PART_Test: INSERT: %s" % element) elif 'arp' in data: if data['arp'] == 1: ip = data['SPA'] mac = data['SHA'] part = data['participant'] if part not in self.nhpart_2_VNHs: self.nhpart_2_VNHs[part] = [] if ip not in self.nhpart_2_VNHs[part]: self.nhpart_2_VNHs[part].append(ip) newbest = (part, mac) if ip not in self.arp_table: self.arp_table[ip] = ARPEntry(newbest, None) else: ae = self.arp_table[ip] # Modify only if it is an actual change if self.arp_table[ip].best_hop != newbest: self.arp_table[ip] = ARPEntry(newbest, ae.best_hop) else: (requester_srcmac, requested_vnh) = tuple(data['arp']) self.logger.debug("Event Received: ARP request for IP " + str(requested_vnh)) self.process_arp_request(requester_srcmac, requested_vnh) else: self.logger.warn("UNKNOWN EVENT TYPE RECEIVED: " + str(data)) def process_message(self, msg): mtype = msg["msg_type"] if mtype == "linkdown": part = msg["participant"] if part not in self.nhpart_2_VNHs: return vnhs = self.nhpart_2_VNHs[part] for v in vnhs: best = self.arp_table[v].best_hop second = self.arp_table[v].prev_hop if part == best[0] and second: # Send ARP with available second best-hop for port in self.cfg.ports: self.process_arp_request(port["MAC"], v, second[1]) def process_policy_changes(self, change_info, mod_type): # idea to remove flow rules for the old policies with cookies ''' removal_msgs = [] for element in change_info: if 'removal_cookies' in element: for cookie in element['removal_cookies']: cookie_id = (cookie['cookie'],65535) match_args = cookie['match'] mod = {"rule_type":"inbound", "priority":4,"match":{} , "action":{}, "cookie":cookie_id, "mod_type":"remove"} removal_msgs.append(mod) self.dp_queued.extend(removal_msgs) ''' # json file format for change_info - mod_type = remove or insert ''' { "policy": [ { mod_type: [ # change_info begin { "inbound": [ { cookie1 ... match ... action } { cookie2 ... match ... action } ] } { "outbound": [ { cookie1 ... match ... action } { cookie2 ... match ... action } ] } # change_info end ] // end mod_type-array }, { mod_type: ... } ] // end policy-array } ''' policies = self.sanitize_policies(change_info) final_switch = "main-in" if self.cfg.isMultiTableMode(): final_switch = "main-out" #self.init_vnh_assignment() // not used inbound_policies = {} outbound_policies = {} for element in policies: if 'inbound' in element: inbound_policies = element if 'outbound' in element: outbound_policies = element #self.logger.debug("PART_Test: INBOUND: %s" % inbound_policies) #self.logger.debug("PART_Test: OUTBOUND: %s" % outbound_policies) rule_msgs = init_inbound_rules(self.id, inbound_policies, self.supersets, final_switch) rule_msgs2 = init_outbound_rules(self, self.id, outbound_policies, self.supersets, final_switch) if 'changes' in rule_msgs2: if 'changes' not in rule_msgs: rule_msgs['changes'] = [] rule_msgs['changes'] += rule_msgs2['changes'] for rule in rule_msgs['changes']: rule['mod_type'] = mod_type #self.logger.debug("PART_Test: Rule Msgs: %s" % rule_msgs) if 'changes' in rule_msgs: self.dp_queued.extend(rule_msgs["changes"]) self.push_dp() def process_bgp_route(self, route): "Process each incoming BGP advertisement" tstart = time.time() # Map to update for each prefix in the route advertisement. updates = self.bgp_instance.update(route) #self.logger.debug("process_bgp_route:: "+str(updates)) # TODO: This step should be parallelized # TODO: The decision process for these prefixes is going to be same, we # should think about getting rid of such redundant computations. for update in updates: self.bgp_instance.decision_process_local(update) self.vnh_assignment(update) if TIMING: elapsed = time.time() - tstart self.logger.debug("Time taken for decision process: " + str(elapsed)) tstart = time.time() if self.cfg.isSupersetsMode(): ################## SUPERSET RESPONSE TO BGP ################## # update supersets "Map the set of BGP updates to a list of superset expansions." ss_changes, ss_changed_prefs = self.supersets.update_supersets( self, updates) if TIMING: elapsed = time.time() - tstart self.logger.debug("Time taken to update supersets: " + str(elapsed)) tstart = time.time() # ss_changed_prefs are prefixes for which the VMAC bits have changed # these prefixes must have gratuitous arps sent garp_required_vnhs = [ self.prefix_2_VNH[prefix] for prefix in ss_changed_prefs ] "If a recomputation event was needed, wipe out the flow rules." if ss_changes["type"] == "new": self.logger.debug("Wiping outbound rules.") wipe_msgs = msg_clear_all_outbound(self.policies, self.port0_mac) self.dp_queued.extend(wipe_msgs) #if a recomputation was needed, all VMACs must be reARPed # TODO: confirm reARPed is a word garp_required_vnhs = self.VNH_2_prefix.keys() if len(ss_changes['changes']) > 0: self.logger.debug("Supersets have changed: " + str(ss_changes)) "Map the superset changes to a list of new flow rules." flow_msgs = update_outbound_rules(ss_changes, self.policies, self.supersets, self.port0_mac) self.logger.debug("Flow msgs: " + str(flow_msgs)) "Dump the new rules into the dataplane queue." self.dp_queued.extend(flow_msgs) if TIMING: elapsed = time.time() - tstart self.logger.debug("Time taken to deal with ss_changes: " + str(elapsed)) tstart = time.time() ################## END SUPERSET RESPONSE ################## else: # TODO: similar logic for MDS self.logger.debug("Creating ctrlr messages for MDS scheme") if TIMING: elapsed = time.time() - tstart self.logger.debug("Time taken to push dp msgs: " + str(elapsed)) tstart = time.time() changed_vnhs, announcements = self.bgp_instance.bgp_update_peers( updates, self.prefix_2_VNH, self.cfg.ports) """ Combine the VNHs which have changed BGP default routes with the VNHs which have changed supersets. """ changed_vnhs = set(changed_vnhs) changed_vnhs.update(garp_required_vnhs) # Send gratuitous ARP responses for all them # for vnh in changed_vnhs: # self.process_arp_request(None, vnh) # Tell Route Server that it needs to announce these routes # for announcement in announcements: # # TODO: Complete the logic for this function # self.send_announcement(announcement) if TIMING: elapsed = time.time() - tstart self.logger.debug("Time taken to send garps/announcements: " + str(elapsed)) tstart = time.time() return self.push_dp() def vnh_assignment(self, update): "Assign VNHs for the advertised prefixes" if self.cfg.isSupersetsMode(): " Superset" # TODO: Do we really need to assign a VNH for each advertised prefix? if ('announce' in update): prefix = update['announce'].prefix if (prefix not in self.prefix_2_VNH): # get next VNH and assign it the prefix self.num_VNHs_in_use += 1 vnh = str(self.cfg.VNHs[self.num_VNHs_in_use]) self.prefix_2_VNH[prefix] = vnh self.VNH_2_prefix[vnh] = prefix else: "Disjoint" # TODO: @Robert: Place your logic here for VNH assignment for MDS scheme self.logger.debug("VNH assignment called for disjoint vmac_mode") def init_vnh_assignment(self): "Assign VNHs for the advertised prefixes" if self.cfg.isSupersetsMode(): " Superset" # TODO: Do we really need to assign a VNH for each advertised prefix? #self.bgp_instance.rib["local"].dump() prefixes = self.bgp_instance.rib.get_local_prefixes() #print 'init_vnh_assignment: prefixes:', prefixes #print 'init_vnh_assignment: prefix_2_VNH:', self.prefix_2_VNH for prefix in prefixes: if (prefix not in self.prefix_2_VNH): # get next VNH and assign it the prefix self.num_VNHs_in_use += 1 vnh = str(self.cfg.VNHs[self.num_VNHs_in_use]) self.prefix_2_VNH[prefix] = vnh self.VNH_2_prefix[vnh] = prefix else: "Disjoint" # TODO: @Robert: Place your logic here for VNH assignment for MDS scheme self.logger.debug("VNH assignment called for disjoint vmac_mode")
class GSS(object): def __init__(self, logger, sender, config): self.logger = logger self.sender = sender self.config = config self.fm_builder = FlowModMsgBuilder(0, self.config.flanc_auth["key"]) self.vmac_builder = VMACBuilder(self.config.vmac_options) def handle_BGP(self, rule_type): ### BGP traffic to route server port = self.config.route_server.ports[0] action = {"fwd": [port.id]} match = {"eth_dst": port.mac, "tcp_src": BGP} self.fm_builder.add_flow_mod("insert", rule_type, "bgp", match, action) match = {"eth_dst": port.mac, "tcp_dst": BGP} self.fm_builder.add_flow_mod("insert", rule_type, "bgp", match, action) ### BGP traffic to participants for participant in self.config.peers.values(): for port in participant.ports: match = {"eth_dst": port.mac, "tcp_src": BGP} action = {"fwd": [port.id]} self.fm_builder.add_flow_mod("insert", rule_type, "bgp", match, action) match = {"eth_dst": port.mac, "tcp_dst": BGP} self.fm_builder.add_flow_mod("insert", rule_type, "bgp", match, action) def handle_ARP_in_main(self, rule_type): ### direct all ARP responses for the route server to it port = self.config.route_server.ports[0] match = {"eth_type": ETH_TYPE_ARP, "eth_dst": port.mac} action = {"fwd": [port.id]} self.fm_builder.add_flow_mod("insert", rule_type, "arp", match, action) for participant in self.config.peers.values(): ### make sure ARP replies reach the participants for port in participant.ports: match = {"eth_type": ETH_TYPE_ARP, "eth_dst": port.mac} action = {"fwd": [port.id]} self.fm_builder.add_flow_mod("insert", rule_type, "arp", match, action) ### direct gratuituous ARPs only to the respective participant i = 0 for port in participant.ports: vmac = self.vmac_builder.part_port_match(participant.name, i, inbound_bit=False) vmac_mask = self.vmac_builder.part_port_mask(False) match = { "in_port": "arp", "eth_type": ETH_TYPE_ARP, "eth_dst": (vmac, vmac_mask) } action = {"set_eth_dst": MAC_BROADCAST, "fwd": [port.id]} self.fm_builder.add_flow_mod("insert", rule_type, "arp", match, action) i += 1 ### flood ARP requests that have gone through the arp switch, but only on non switch-switch ports match = { "in_port": "arp", "eth_type": ETH_TYPE_ARP, "eth_dst": MAC_BROADCAST } ports = [] for participant in self.config.peers.values(): for port in participant.ports: ports.append(port.id) ports.append(self.config.route_server.ports[0].id) action = {"fwd": ports} self.fm_builder.add_flow_mod("insert", rule_type, "arp_broadcast", match, action) ### forward all ARP requests to the arp switch match = {"eth_type": ETH_TYPE_ARP} action = {"fwd": ["arp"]} self.fm_builder.add_flow_mod("insert", rule_type, "arp_filter", match, action) def handle_ARP_in_arp(self, rule_type): ### direct ARP requests for VNHs to ARP proxy port = self.config.arp_proxy.ports[0] match = { "in_port": "main", "eth_type": ETH_TYPE_ARP, "arp_tpa": (str(self.config.vnhs.network), str(self.config.vnhs.netmask)) } action = {"fwd": [port.id]} self.fm_builder.add_flow_mod("insert", rule_type, "vnh_arp", match, action) ### send all other ARP requests back match = {"eth_type": ETH_TYPE_ARP, "in_port": "main"} action = {"fwd": [OFPP_IN_PORT]} self.fm_builder.add_flow_mod("insert", rule_type, "default", match, action) ### send all ARP replies from the ARP proxy to the main switch match = {"eth_type": ETH_TYPE_ARP, "in_port": "arp proxy"} action = {"fwd": ["main"]} self.fm_builder.add_flow_mod("insert", rule_type, "default", match, action) def handle_participant_with_outbound(self, rule_type): for participant in self.config.peers.values(): ### outbound policies specified if participant.outbound_rules: mac = None for port in participant.ports: if mac is None: mac = port.mac match = {"in_port": port.id} action = {"set_eth_src": mac, "fwd": ["outbound"]} self.fm_builder.add_flow_mod("insert", rule_type, "outbound", match, action) def handle_participant_with_inbound(self, rule_type, mask_inbound_bit): for participant in self.config.peers.values(): ### inbound policies specified if participant.inbound_rules: i = 0 for port in participant.ports: vmac = self.vmac_builder.part_port_match( participant.name, i, False) i += 1 vmac_mask = self.vmac_builder.part_port_mask( mask_inbound_bit) match = {"eth_dst": (vmac, vmac_mask)} action = {"set_eth_dst": port.mac, "fwd": [port.id]} self.fm_builder.add_flow_mod("insert", rule_type, "output", match, action) def default_forwarding(self, rule_type): for participant in self.config.peers.values(): ### default forwarding if not participant.inbound_rules: vmac = self.vmac_builder.next_hop_match( participant.name, False) vmac_mask = self.vmac_builder.next_hop_mask(False) port = participant.ports[0] print "VMAC default rule match:", (vmac, vmac_mask) match = {"eth_dst": (vmac, vmac_mask)} action = {"set_eth_dst": port.mac, "fwd": [port.id]} self.fm_builder.add_flow_mod("insert", rule_type, "output", match, action) def default_forwarding_inbound(self, rule_type, fwd): ## set the inbound bit to zero for participant in self.config.peers.values(): if participant.inbound_rules: port = participant.ports[0] vmac_match = self.vmac_builder.next_hop_match( participant.name, False) vmac_match_mask = self.vmac_builder.next_hop_mask(False) vmac_action = self.vmac_builder.part_port_match( participant.name, 0, False) print "VMAC default rule match:", (vmac_match, vmac_match_mask) match = {"eth_dst": (vmac_match, vmac_match_mask)} action = {"set_eth_dst": vmac_action, "fwd": [fwd]} self.fm_builder.add_flow_mod("insert", "inbound", "inbound", match, action) def handle_inbound(self, rule_type): vmac = self.vmac_builder.only_first_bit() match = {"eth_dst": (vmac, vmac)} action = {"fwd": ["outbound"]} self.fm_builder.add_flow_mod("insert", rule_type, "inbound", match, action) def match_any_fwd(self, rule_type, dst): match = {} action = {"fwd": [dst]} self.fm_builder.add_flow_mod("insert", rule_type, "default", match, action) def delete_flow_rule(self, rule_type, cookie, cookie_mask): self.fm_builder.delete_flow_mod("remove", rule_type, cookie, cookie_mask) def start(self): self.logger.info('start') self.init_fabric() self.sender.send(self.fm_builder.get_msg()) self.logger.info('sent flow mods to reference monitor')
class MDS(object): def __init__(self, logger, sender, config): self.logger = logger self.sender = sender self.config = config self.fm_builder = FlowModMsgBuilder(0, self.config.flanc_auth["key"]) def handle_BGP(self, rule_type): ### BGP traffic to route server port = self.config.route_server.ports[0] action = {"fwd": [port.id]} match = {"eth_dst": port.mac, "tcp_src": BGP} self.fm_builder.add_flow_mod("insert", rule_type, BGP_PRIORITY, match, action) match = {"eth_dst": port.mac, "tcp_dst": BGP} self.fm_builder.add_flow_mod("insert", rule_type, BGP_PRIORITY, match, action) ### BGP traffic to participants for participant in self.config.peers.values(): for port in participant.ports: match = {"eth_dst": port.mac, "tcp_src": BGP} action = {"fwd": [port.id]} self.fm_builder.add_flow_mod("insert", rule_type, BGP_PRIORITY, match, action) match = {"eth_dst": port.mac, "tcp_dst": BGP} self.fm_builder.add_flow_mod("insert", rule_type, BGP_PRIORITY, match, action) def handle_ARP(self, rule_type): ### direct ARP requests for VNHs to ARP proxy port = self.config.arp_proxy.ports[0] match = {"eth_type": ETH_TYPE_ARP, "arp_tpa": (str(self.config.vnhs.network), str(self.config.vnhs.netmask))} action = {"fwd": [port.id]} self.fm_builder.add_flow_mod("insert", rule_type, ARP_PRIORITY, match, action) ### direct all ARP requests for the route server to it port = self.config.route_server.ports[0] match = {"eth_type": ETH_TYPE_ARP, "eth_dst": port.mac} action = {"fwd": [port.id]} self.fm_builder.add_flow_mod("insert", rule_type, ARP_PRIORITY, match, action) for participant in self.config.peers.values(): ### make sure ARP replies reach the participants for port in participant.ports: match = {"eth_type": ETH_TYPE_ARP, "eth_dst": port.mac} action = {"fwd": [port.id]} self.fm_builder.add_flow_mod("insert", rule_type, ARP_PRIORITY, match, action) ### flood ARP requests match = {"eth_type": ETH_TYPE_ARP, "eth_dst": MAC_BROADCAST} ports = [] for participant in self.config.peers.values(): for port in participant.ports: ports.append(port.id) ports.append(self.config.arp_proxy.ports[0].id) ports.append(self.config.route_server.ports[0].id) action = {"fwd": ports} self.fm_builder.add_flow_mod("insert", rule_type, ARP_PRIORITY, match, action) def handle_participant_with_outbound(self, rule_type): for participant in self.config.peers.values(): ### outbound policies specified if participant.outbound_rules: mac = None for port in participant.ports: if mac is None: mac = port.mac match = {"in_port": port.id} action = {"set_eth_src": mac, "fwd": ["outbound"]} self.fm_builder.add_flow_mod("insert", rule_type, OUTBOUND_PRIORITY, match, action) def handle_participant_with_inbound(self, rule_type): for participant in self.config.peers.values(): ### send all traffic for participants with inbound policies to inbound handler if participant.inbound_rules: for port in participant.ports: match = {"eth_dst": port.mac} action = {"fwd": ["inbound"]} self.fm_builder.add_flow_mod("insert", rule_type, INBOUND_PRIORITY, match, action) def default_forwarding(self, rule_type): for participant in self.config.peers.values(): ### default forwarding if not participant.inbound_rules: port = participant.ports[0] match = {"eth_dst": port.mac} action = {"fwd": [port.id]} self.fm_builder.add_flow_mod("insert", rule_type, FORWARDING_PRIORITY, match, action) def default_forwarding_inbound(self, rule_type, in_port): ### default forwarding for traffic to participants with inbound policies for participant in self.config.peers.values(): if participant.inbound_rules: for port in participant.ports: match = {"eth_dst": port.mac} if in_port: match["in_port"] = 1 action = {"fwd": [port.id]} self.fm_builder.add_flow_mod("insert", rule_type, FORWARDING_PRIORITY, match, action) def match_any_fwd(self, rule_type, dst): match = {} action = {"fwd": [dst]} self.fm_builder.add_flow_mod("insert", rule_type, DEFAULT_PRIORITY, match, action) def start(self): self.logger.info('start') self.init_fabric() self.sender.send(self.fm_builder.get_msg()) self.logger.info('sent flow mods to reference monitor')