# Copyright (C) 2011 Nippon Telegraph and Telephone Corporation. | |
# | |
# Licensed under the Apache License, Version 2.0 (the "License"); | |
# you may not use this file except in compliance with the License. | |
# You may obtain a copy of the License at | |
# | |
# http://www.apache.org/licenses/LICENSE-2.0 | |
# | |
# Unless required by applicable law or agreed to in writing, software | |
# distributed under the License is distributed on an "AS IS" BASIS, | |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | |
# implied. | |
# See the License for the specific language governing permissions and | |
# limitations under the License. | |
import logging | |
from ryu.base import app_manager | |
from time import sleep | |
from ryu.controller import ofp_event | |
from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER | |
from ryu.controller.handler import set_ev_cls | |
from ryu.ofproto import ofproto_v1_3 | |
from ryu.lib.packet import packet | |
from ryu.lib.packet import ethernet | |
from ryu.lib import addrconv | |
LOG = logging.getLogger('ryu.app.pon_topology') | |
class PonTopology13(app_manager.RyuApp): | |
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] | |
def __init__(self, *args, **kwargs): | |
super(PonTopology13, self).__init__(*args, **kwargs) | |
self.mac_to_port = {} | |
@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER) | |
def switch_features_handler(self, ev): | |
datapath = ev.msg.datapath | |
# This does nothing if flows have not been previously configured in the OF agent | |
self.del_all_flows(datapath) | |
# Configure the flows (VID 100) | |
# | |
# Ports 1-128 are implicitly mapped to UNI-0 on ONU 1->128 | |
# Ports 129 and above are implicitly mapped to OLT NNI-0 and above | |
self.add_vid_flow(datapath,10000, 1, 129, 100, 0) | |
self.add_vid_flow(datapath,10001, 129, 1, 100, 0) | |
sleep(1) | |
self.send_barrier(datapath) | |
sleep(5) | |
self.del_all_flows(datapath) | |
@set_ev_cls(ofp_event.EventOFPPortStatus, MAIN_DISPATCHER) | |
def port_status_handler(self, ev): | |
LOG.debug('port_status_handler port id: %d', ev.msg.desc.port_no) | |
def add_meter(self, datapath, meter_id, rate): | |
ofproto = datapath.ofproto | |
parser = datapath.ofproto_parser | |
band = parser.OFPMeterBandDrop(burst_size=0, rate=rate) | |
mod = parser.OFPMeterMod(datapath=datapath,command=ofproto.OFPMC_ADD, flags=ofproto.OFPMF_KBPS, meter_id=meter_id, bands=[band]) | |
LOG.info("add_meter: meter_id=%d, rate=%d KBPS") | |
datapath.send_msg(mod) | |
def add_vid_flow(self, datapath, cookie, src_port, dst_port, vid, meter_id): | |
ofproto = datapath.ofproto | |
parser = datapath.ofproto_parser | |
actions = [parser.OFPActionOutput(dst_port)] | |
if meter_id != 0: | |
inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,actions), parser.OFPInstructionMeter(meter_id)] | |
else: | |
inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,actions)] | |
# NOTE: 0x1000 is OR'd into the vid to set the OFPVID_PRESENT flag in the OpenFlow FLOW_MOD (OFPFC_ADD) | |
# message match field. | |
match = parser.OFPMatch(in_port=src_port, vlan_vid=(vid | 0x1000)) | |
mod = parser.OFPFlowMod(datapath=datapath, | |
cookie=cookie, | |
cookie_mask=32767, | |
priority=0, | |
match=match, | |
instructions=inst) | |
LOG.info("add_vid_flow: src_port=%d dst_port=%d vid=%d meter=%d cookie=%d", | |
src_port, dst_port, vid, meter_id, cookie) | |
datapath.send_msg(mod) | |
def del_flow(self, datapath, cookie): | |
LOG.info("del_flow: cookie=%d", cookie) | |
self._del_flow(datapath, cookie, 32767) | |
def del_all_flows(self, datapath): | |
LOG.info("del_all_flows") | |
# Cookie 0 (argument 2) tells the OF agent to delete all configured flows | |
self._del_flow(datapath, 0, 0) | |
def _del_flow(self, datapath, cookie, mask): | |
ofproto = datapath.ofproto | |
parser = datapath.ofproto_parser | |
mod = parser.OFPFlowMod( | |
datapath=datapath, match=None, cookie=cookie, cookie_mask=mask, | |
command=ofproto.OFPFC_DELETE) | |
datapath.send_msg(mod) | |
def send_barrier(self, datapath): | |
LOG.info("send_barrier") | |
datapath.send_barrier() | |