According to the OpenFlow contract [ofp1.0-38], when the physical port OvS DataPath added, changed or deleted. Will run the detailed action first. The controller is then informed by Ofp_port_status asynchronous messages, such as when we run a command such as Ovs-vsctl Add-port br0 eth0, the OVSDB database is updated. The global variable reconfiguring becomes true at one polling time, and this OvS is configured again.
if (reconfiguring) {///CFG entries can be traced to a configuration change in Ovsdb if (cfg) { if (!reconf_txn) { Reconf_txn = Ovsdb_idl_txn_ Create (IDL); } Configure each CFG again, core Ingress if (bridge_reconfigure_continue (cfg)) { ovsrec_open_vswitch_set_cur_cfg (cfg, cfg-> NEXT_CFG); } } else { bridge_reconfigure_continue (&null_cfg); } }
Next, run the configuration in detail:
static boolbridge_reconfigure_continue (const struct Ovsrec_open_vswitch *ovs_cfg) {struct sockaddr_in *managers; int sflow_bridge_number; size_t N_managers; struct Bridge *br; BOOL done; ASSERT (reconfiguring);//Reconfigure First thing to do is to delete the old port, and then build a new port based on the configuration done = BRIDGE_RECONFIGURE_OFP (); /* Complete the configuration. */sflow_bridge_number = 0; Collect_in_band_managers (Ovs_cfg, &managers, &n_managers); Hmap_for_each (BR, node, &all_bridges) {struct Port *port; /* We need the DataPath ID early to allow LACP ports to use it as the * default system ID. */bridge_configure_datapath_id (BR); Hmap_for_each (port, Hmap_node, &br->ports) {struct iface *iface; Port_configure (port); List_for_each (Iface, Port_elem, &port->ifaces) {iface_configure_cfm (iface); Iface_configure_qos (Iface, Port->cfg->qos); Iface_set_mac (Iface); }} bridge_configure_mirrors (BR); Bridge_configure_flow_eviction_threshold (BR); BRIDGE_CONFIGURE_FORWARD_BPDU (BR); Bridge_configure_mac_idle_time (BR); Bridge_configure_remotes (BR, managers, n_managers); Bridge_configure_netflow (BR); Bridge_configure_sflow (BR, &sflow_bridge_number); BRIDGE_CONFIGURE_STP (BR); Bridge_configure_tables (BR); } free (managers); if (done) {/* Ovs-vswitchd have completed initialization, so allow the process that * forked us to exit suc Cessfully. */Daemonize_complete (); reconfiguring = false; Vlog_info ("%s (Open vSwitch)%s", program_name, VERSION); } return done;}
Delete all the ports first, then add:
Static BOOLBRIDGE_RECONFIGURE_OFP (void) {long long int deadline; struct Bridge *br; Time_refresh (); Deadline = Time_msec () + Ofp_port_action_window; /* The kernel would reject any attempt to add a given port to a datapath if * This port already belongs to a different DataPath, so we must does all * ports deletions before any port additions. */Hmap_for_each (BR, node, &all_bridges) {struct ofpp_garbage *garbage, *next; List_for_each_safe (Garbage, Next, List_node, &br->ofpp_garbage) {/* It ' s a bit dangerous to call BRIDG E_run_fast () Here as Ofproto's * internal datastructures may is not consistent. Eventually, when * port additions and deletions is cheaper, these calls should be * removed. */Bridge_run_fast (); Ofproto_port_del (Br->ofproto, Garbage->ofp_port); List_remove (&garbage->list_node); Free (garbage); Time_refresh (); if (Time_msec () >= deadline) {return false; } bridge_run_fast (); }} hmap_for_each (BR, node, &all_bridges) {struct if_cfg *if_cfg, *next; Hmap_for_each_safe (If_cfg, Next, Hmap_node, &br->if_cfg_todo) {//Here is the core, add an interface on our OvS bridge Iface_crea Te (BR, If_cfg,-1); Time_refresh (); if (Time_msec () >= deadline) {return false; }}} return true;
add a interface to the BR according to the configuration if_cfg, assuming that the specified openflowport number is negative. Indicates that you are actively assigning:
Static booliface_create (struct bridge *br, struct if_cfg *if_cfg, int ofp_port) {const struct Ovsrec_interface *iface_c FG = if_cfg->cfg; const struct Ovsrec_port *port_cfg = if_cfg->parent; struct Netdev *netdev; struct Iface *iface; struct Port *port; int error; /* Get rid of ' if_cfg ' itself. We already copied out the interesting * bits. */Hmap_remove (&br->if_cfg_todo, &if_cfg->hmap_node); Free (IF_CFG); /* Do the bits, the can fail up front. * * It's a bit dangerous to call Bridge_run_fast () here as Ofproto's * internal datastructures may is not consiste Nt. Eventually, when Port * additions and deletions is cheaper, these calls should be removed. */Bridge_run_fast (); ASSERT (!iface_lookup (BR, iface_cfg->name)); Error = Iface_do_create (BR, Iface_cfg, Port_cfg, &ofp_port, &netdev); Bridge_run_fast (); if (Error) {Iface_clear_db_record (iface_cfg); return false; }/* Get or create the port structure. */port = port_lookup (BR, port_cfg->name); if (!port) {port = Port_create (BR, port_cfg); }/* Create the IFACE structure. */iface = xzalloc (sizeof *iface); List_push_back (&port->ifaces, &iface->port_elem); Hmap_insert (&br->iface_by_name, &iface->name_node, hash_string (iface_cfg->name, 0)); Iface->port = port; Iface->name = Xstrdup (iface_cfg->name); Iface->ofp_port =-1; Iface->netdev = Netdev; Iface->type = Iface_get_type (iface_cfg, br->cfg); Iface->cfg = iface_cfg; Iface_set_ofp_port (Iface, Ofp_port); /* Populate initial status in database. */Iface_refresh_stats (iface); Iface_refresh_status (Iface); /* ADD bond fake iface if necessary. */if (Port_is_bond_fake_iface (port)) {struct Ofproto_port ofproto_port; if (Ofproto_port_query_by_name (Br->ofproto, Port->name, &ofproto_port) {struct Netdev *netdev; int error; Error = Netdev_open (port->name, "internal", &netdev); if (!error) {//Add this network device to our OpenFlow switch Ofproto_port_add (Br->ofproto, Netdev, NULL); Netdev_close (Netdev); } else {Vlog_warn ("Could not open network device%s (%s)", Port->name, Strerro R (Error)); }} else {/* already exists, nothing to do. */Ofproto_port_destroy (&ofproto_port); }} return true;
Call Ofproto (OpenFlow SW Interface) to implement the Port_add method in detail:
Intofproto_port_add (struct Ofproto *ofproto, struct Netdev *netdev, uint16_t *ofp_portp) { uint16_t ofp_port; int error; Error = Ofproto->ofproto_class->port_add (Ofproto, Netdev, &ofp_port);//See Dpif_linux_class's Detailed implementation if (! Error) {//update our openflow switch (i.e. Ofproto) Update_port (Ofproto, Netdev_get_name (Netdev)); } if (OFP_PORTP) { *OFP_PORTP = error? Ofpp_none:ofp_port; } return error;}
Static Voidupdate_port (struct Ofproto *ofproto, const char *name) {struct Ofproto_port ofproto_port; struct Ofputil_phy_port pp; struct Netdev *netdev; struct Ofport *port; Coverage_inc (Ofproto_update_port); /* Fetch ' name ' s location and properties from the DataPath. */Netdev = (!ofproto_port_query_by_name (ofproto, name, &ofproto_port)? Ofport_open (Ofproto, &OFP Roto_port, &PP): NULL); if (netdev) {port = Ofproto_get_port (Ofproto, Ofproto_port.ofp_port); if (Port &&!strcmp (Netdev_get_name (Port->netdev), name)) {struct Netdev *old_netdev = port->net Dev /* ' name ' hasn ' t changed location. Any properties changed? */if (!ofport_equal (&PORT->PP, &pp)) {ofport_modified (port, &PP); } update_mtu (Ofproto, Port); /* Install The newly opened Netdev in case it has changed. * Don ' t close the old Netdev Yet in case port_modified have to * remove a retained reference to it.*/Port->netdev = n Etdev; Port->change_seq = Netdev_change_seq (Netdev); if (port->ofproto->ofproto_class->port_modified) {Port->ofproto->ofproto_class->port_mod Ified (port); } netdev_close (Old_netdev); } else {/* If ' port ' is nonnull then its name differs from ' name ' and thus * we should delete it. If we think there ' s a port named ' name ' * then its port number must is wrong now so delete it too. */if (port) {ofport_remove (port); } ofport_remove_with_name (Ofproto, name);//See here Ofport_install (Ofproto, Netdev, &pp); }} else {/* Any port named ' name ' was gone now. */Ofport_remove_with_name (Ofproto, name); } Ofproto_port_destroy (&ofproto_port);}
Static Voidofport_install (struct Ofproto *p, struct netdev *netdev, const struct Ofputil_phy_port *pp) {C Onst char *netdev_name = netdev_get_name (Netdev); struct Ofport *ofport; int error; /* Create Ofport. */Ofport = P->ofproto_class->port_alloc (); if (!ofport) {error = Enomem; Goto error; } Ofport->ofproto = P; Ofport->netdev = Netdev; Ofport->change_seq = Netdev_change_seq (Netdev); OFPORT->PP = *pp; Ofport->ofp_port = pp->port_no; /* ADD port to ' P '. */Hmap_insert (&p->ports, &ofport->hmap_node, Hash_int (ofport->ofp_port, 0)); Shash_add (&p->port_by_name, Netdev_name, Ofport); UPDATE_MTU (P, ofport); /* Let the Ofproto_class initialize its private data. */error = p->ofproto_class->port_construct (Ofport); if (Error) {goto error; After the}//update operation is complete. Send notification message to Controller connmgr_send_port_status (P->connmgr, pp, ofppr_add); Return;error: VLOG_WARN_RL (&RL, "%s:could not add port%s (%s)", P->name, Netdev_name, strerror (Error)); if (ofport) {ofport_destroy__ (ofport); } else {netdev_close (Netdev); }}
send Port_status and Port change Reasons to SDN Controller:
Voidconnmgr_send_port_status (struct connmgr *mgr, const struct Ofputil_phy_port *pp, uint8_t reason) {/ * XXX Should limit the number of queued port status change messages. */ struct ofputil_port_status PS; struct Ofconn *ofconn; Ps.reason = reason; Ps.desc = *pp; List_for_each (Ofconn, node, &mgr->all_conns) { if (ofconn_receives_async_msg (Ofconn, Oam_port_status, Reason) { struct ofpbuf *msg; msg = Ofputil_encode_port_status (&ps, ofconn->protocol); Ofconn_send (Ofconn, MSG, NULL);}}}
Copyright notice: This article Bo Master original article. Blog, not reproduced without consent.
OVS PI Ofpt_port_status Process