summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorKazuya Goda <goda@cvs.openbsd.org>2016-09-02 10:01:37 +0000
committerKazuya Goda <goda@cvs.openbsd.org>2016-09-02 10:01:37 +0000
commit0f590a8a07c19d851259836004e21db0adaff2d3 (patch)
tree1ae40839194b9e2cac0fdd0c01a5ddb409acc76a /sys
parent02647f4aae7f5879d92879db066a50420a432865 (diff)
Add switch(4) support to ifconfig
ok deraadt@ yasuoka@ reyk@ henning@
Diffstat (limited to 'sys')
-rw-r--r--sys/net/if_bridge.c6
-rw-r--r--sys/net/if_bridge.h18
-rw-r--r--sys/net/if_switch.c137
-rw-r--r--sys/net/switchofp.c64
-rw-r--r--sys/sys/sockio.h13
5 files changed, 221 insertions, 17 deletions
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
index ca79aaf0646..80c4b7e67ec 100644
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_bridge.c,v 1.282 2016/09/01 10:06:33 goda Exp $ */
+/* $OpenBSD: if_bridge.c,v 1.283 2016/09/02 10:01:36 goda Exp $ */
/*
* Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
@@ -117,11 +117,7 @@ void bridge_span(struct bridge_softc *, struct mbuf *);
void bridge_stop(struct bridge_softc *);
void bridge_init(struct bridge_softc *);
int bridge_bifconf(struct bridge_softc *, struct ifbifconf *);
-
int bridge_blocknonip(struct ether_header *, struct mbuf *);
-struct mbuf *bridge_ip(struct bridge_softc *, int, struct ifnet *,
- struct ether_header *, struct mbuf *m);
-int bridge_ifenqueue(struct bridge_softc *, struct ifnet *, struct mbuf *);
void bridge_ifinput(struct ifnet *, struct mbuf *);
int bridge_dummy_output(struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *);
diff --git a/sys/net/if_bridge.h b/sys/net/if_bridge.h
index f7d8c97a974..df1a3b9f534 100644
--- a/sys/net/if_bridge.h
+++ b/sys/net/if_bridge.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_bridge.h,v 1.49 2016/09/01 10:06:33 goda Exp $ */
+/* $OpenBSD: if_bridge.h,v 1.50 2016/09/02 10:01:36 goda Exp $ */
/*
* Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
@@ -45,7 +45,7 @@ struct ifbreq {
char ifbr_name[IFNAMSIZ]; /* bridge ifs name */
char ifbr_ifsname[IFNAMSIZ]; /* member ifs name */
u_int32_t ifbr_ifsflags; /* member ifs flags */
- u_int8_t ifbr_portno; /* member port number */
+ u_int32_t ifbr_portno; /* member port number */
u_int8_t ifbr_state; /* member stp state */
u_int8_t ifbr_priority; /* member stp priority */
@@ -71,7 +71,8 @@ struct ifbreq {
#define IFBIF_BSTP_PTP 0x0040 /* member stp ptp */
#define IFBIF_BSTP_AUTOPTP 0x0080 /* member stp autoptp enabled */
#define IFBIF_SPAN 0x0100 /* ifs is a span port (ro) */
-#define IFBIF_RO_MASK 0xff00 /* read only bits */
+#define IFBIF_LOCAL 0x1000 /* local port in switch(4) */
+#define IFBIF_RO_MASK 0x0f00 /* read only bits */
/* SIOCBRDGFLUSH */
#define IFBF_FLUSHDYN 0x0 /* flush dynamic addresses only */
@@ -152,6 +153,8 @@ struct ifbrparam {
u_int8_t ifbrpu_maxage; /* max age (sec) */
u_int8_t ifbrpu_proto; /* bridge protocol */
u_int8_t ifbrpu_txhc; /* bpdu tx holdcount */
+ u_int64_t ifbrpu_datapath; /* datapath-id */
+ u_int32_t ifbrpu_maxgroup; /* group size */
} ifbrp_ifbrpu;
};
#define ifbrp_csize ifbrp_ifbrpu.ifbrpu_csize
@@ -162,6 +165,9 @@ struct ifbrparam {
#define ifbrp_hellotime ifbrp_ifbrpu.ifbrpu_hellotime
#define ifbrp_fwddelay ifbrp_ifbrpu.ifbrpu_fwddelay
#define ifbrp_maxage ifbrp_ifbrpu.ifbrpu_maxage
+#define ifbrp_datapath ifbrp_ifbrpu.ifbrpu_datapath
+#define ifbrp_maxflow ifbrp_ifbrpu.ifbrpu_csize
+#define ifbrp_maxgroup ifbrp_ifbrpu.ifbrpu_maxgroup
/* Protocol versions */
#define BSTP_PROTO_ID 0x00
@@ -472,8 +478,12 @@ void bridge_timer(void *);
u_int8_t bridge_filterrule(struct brl_head *, struct ether_header *,
struct mbuf *);
void bridge_flushrule(struct bridge_iflist *);
-void bridge_fragment(struct bridge_softc *, struct ifnet *,
+
+struct mbuf *bridge_ip(struct bridge_softc *, int, struct ifnet *,
+ struct ether_header *, struct mbuf *);
+void bridge_fragment(struct bridge_softc *, struct ifnet *,
struct ether_header *, struct mbuf *);
+int bridge_ifenqueue(struct bridge_softc *, struct ifnet *, struct mbuf *);
#endif /* _KERNEL */
#endif /* _NET_IF_BRIDGE_H_ */
diff --git a/sys/net/if_switch.c b/sys/net/if_switch.c
index b8c3529cee7..8f481583981 100644
--- a/sys/net/if_switch.c
+++ b/sys/net/if_switch.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_switch.c,v 1.1 2016/09/01 10:06:33 goda Exp $ */
+/* $OpenBSD: if_switch.c,v 1.2 2016/09/02 10:01:36 goda Exp $ */
/*
* Copyright (c) 2016 Kazuya GODA <goda@openbsd.org>
@@ -121,6 +121,9 @@ struct mbuf
*switch_flow_classifier_ether(struct mbuf *, int *,
struct switch_flow_classify *);
struct mbuf
+ *switch_flow_classifier_tunnel(struct mbuf *, int *,
+ struct switch_flow_classify *);
+struct mbuf
*switch_flow_classifier(struct mbuf *, uint32_t,
struct switch_flow_classify *);
void switch_flow_classifier_dump(struct switch_softc *,
@@ -212,6 +215,8 @@ switch_clone_destroy(struct ifnet *ifp)
TAILQ_FOREACH_SAFE(swpo, &sc->sc_swpo_list, swpo_list_next, tp) {
if ((ifs = if_get(swpo->swpo_ifindex)) != NULL) {
+ if (swpo->swpo_flags & IFBIF_LOCAL)
+ switch_port_unset_local(sc, swpo);
ifs->if_switchport = NULL;
ifpromisc(ifs, 0);
if_ih_remove(ifs, switch_input, NULL);
@@ -307,6 +312,99 @@ discard:
}
int
+switch_port_set_local(struct switch_softc *sc, struct switch_port *swpo)
+{
+ struct switch_port *tswpo;
+ struct ifreq ifreq;
+ struct ifnet *ifs;
+ int error = 0, re_up = 0;
+
+ /*
+ * Only one local interface can exist per switch device.
+ */
+ TAILQ_FOREACH(tswpo, &sc->sc_swpo_list, swpo_list_next) {
+ if (tswpo->swpo_flags & IFBIF_LOCAL)
+ return (EEXIST);
+ }
+
+ ifs = if_get(swpo->swpo_ifindex);
+ if (ifs == NULL)
+ return (ENOENT);
+
+ if (ifs->if_flags & IFF_UP) {
+ re_up = 1;
+ memset(&ifreq, 0, sizeof(ifreq));
+ strlcpy(ifreq.ifr_name, ifs->if_xname, IFNAMSIZ);
+ ifs->if_flags &= ~IFF_UP;
+ ifreq.ifr_flags = ifs->if_flags;
+ error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS, (caddr_t)&ifreq);
+ if (error)
+ goto error;
+ }
+
+ swpo->swpo_flags |= IFBIF_LOCAL;
+ swpo->swpo_port_no = OFP_PORT_LOCAL;
+ swpo->swop_bk_start = ifs->if_start;
+ ifs->if_start = switch_port_ifb_start;
+
+ if (re_up) {
+ memset(&ifreq, 0, sizeof(ifreq));
+ strlcpy(ifreq.ifr_name, ifs->if_xname, IFNAMSIZ);
+ ifs->if_flags &= IFF_UP;
+ ifreq.ifr_flags = ifs->if_flags;
+ error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS, (caddr_t)&ifreq);
+ if (error)
+ goto error;
+ }
+
+ error:
+ if_put(ifs);
+ return (error);
+}
+
+int
+switch_port_unset_local(struct switch_softc *sc, struct switch_port *swpo)
+{
+ struct ifreq ifreq;
+ struct ifnet *ifs;
+ int error = 0, re_up = 0;
+
+ ifs = if_get(swpo->swpo_ifindex);
+ if (ifs == NULL)
+ return (ENOENT);
+
+ if (ifs->if_flags & IFF_UP) {
+ re_up = 1;
+ memset(&ifreq, 0, sizeof(ifreq));
+ strlcpy(ifreq.ifr_name, ifs->if_xname, IFNAMSIZ);
+ ifs->if_flags &= ~IFF_UP;
+ ifreq.ifr_flags = ifs->if_flags;
+ error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS, (caddr_t)&ifreq);
+ if (error)
+ goto error;
+ }
+
+ swpo->swpo_flags &= ~IFBIF_LOCAL;
+ swpo->swpo_port_no = swofp_assign_portno(sc, ifs->if_index);
+ ifs->if_start = swpo->swop_bk_start;
+ swpo->swop_bk_start = NULL;
+
+ if (re_up) {
+ memset(&ifreq, 0, sizeof(ifreq));
+ strlcpy(ifreq.ifr_name, ifs->if_xname, IFNAMSIZ);
+ ifs->if_flags &= IFF_UP;
+ ifreq.ifr_flags = ifs->if_flags;
+ error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS, (caddr_t)&ifreq);
+ if (error)
+ goto error;
+ }
+
+ error:
+ if_put(ifs);
+ return (error);
+}
+
+int
switch_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data)
{
struct ifbaconf *baconf = (struct ifbaconf *)data;
@@ -335,6 +433,24 @@ switch_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data)
case SIOCBRDGIFS:
error = switch_port_list(sc, (struct ifbifconf *)data);
break;
+ case SIOCBRDGADDL:
+ if ((error = suser(curproc, 0)) != 0)
+ break;
+ error = switch_port_add(sc, (struct ifbreq *)data);
+ if (error && error != EEXIST)
+ break;
+ ifs = ifunit(breq->ifbr_ifsname);
+ if (ifs == NULL) {
+ error = ENOENT;
+ break;
+ }
+ swpo = (struct switch_port *)ifs->if_switchport;
+ if (swpo == NULL || swpo->swpo_switch != sc) {
+ error = ESRCH;
+ break;
+ }
+ error = switch_port_set_local(sc, swpo);
+ break;
case SIOCBRDGGIFFLGS:
ifs = ifunit(breq->ifbr_ifsname);
if (ifs == NULL) {
@@ -381,6 +497,13 @@ switch_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data)
brop->ifbop_last_tc_time.tv_sec = bs->bs_last_tc_time.tv_sec;
brop->ifbop_last_tc_time.tv_usec = bs->bs_last_tc_time.tv_usec;
break;
+ case SIOCSWGDPID:
+ case SIOCSWSDPID:
+ case SIOCSWGFLOWMAX:
+ case SIOCSWGMAXGROUP:
+ case SIOCSWSPORTNO:
+ error = swofp_ioctl(ifp, cmd, data);
+ break;
default:
error = ENOTTY;
break;
@@ -521,6 +644,8 @@ switch_port_del(struct switch_softc *sc, struct ifbreq *req)
}
if (swpo) {
+ if (swpo->swpo_flags & IFBIF_LOCAL)
+ switch_port_unset_local(sc, swpo);
ifs->if_switchport = NULL;
ifpromisc(ifs, 0);
if_ih_remove(ifs, switch_input, NULL);
@@ -661,11 +786,17 @@ switch_port_egress(struct switch_softc *sc, struct switch_fwdp_queue *fwdp_q,
len += ETHER_VLAN_ENCAP_LEN;
#endif
- if (((len - ETHER_HDR_LEN) > dst_if->if_mtu))
+ /*
+ * Only if egress port has local port capabilities, it doesn't
+ * need fragment because a frame sends up local network stack.
+ */
+ if (!(swpo->swpo_flags & IFBIF_LOCAL) &&
+ ((len - ETHER_HDR_LEN) > dst_if->if_mtu))
bridge_fragment((struct bridge_softc *)sc,
dst_if, &eh, mc);
else
- switch_ifenqueue(sc, dst_if, mc, 0);
+ switch_ifenqueue(sc, dst_if, mc,
+ (swpo->swpo_flags & IFBIF_LOCAL));
out:
if_put(dst_if);
diff --git a/sys/net/switchofp.c b/sys/net/switchofp.c
index cd8e7408e96..6b9102cf59e 100644
--- a/sys/net/switchofp.c
+++ b/sys/net/switchofp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: switchofp.c,v 1.1 2016/09/01 10:06:33 goda Exp $ */
+/* $OpenBSD: switchofp.c,v 1.2 2016/09/02 10:01:36 goda Exp $ */
/*
* Copyright (c) 2016 Kazuya GODA <goda@openbsd.org>
@@ -1024,9 +1024,53 @@ swofp_assign_portno(struct switch_softc *sc, uint32_t req)
int
swofp_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data)
{
+ struct switch_softc *sc = ifp->if_softc;
+ struct swofp_ofs *swofs = sc->sc_ofs;
+ struct ifbrparam *bparam = (struct ifbrparam *)data;
+ struct ifbreq *breq = (struct ifbreq *)data;
+ struct switch_port *swpo;
+ struct ifnet *ifs;
int error = 0;
switch (cmd) {
+ case SIOCSWGDPID:
+ memcpy(&bparam->ifbrp_datapath, &swofs->swofs_datapath_id,
+ sizeof(uint64_t));
+ break;
+ case SIOCSWSDPID:
+ if ((error = suser(curproc, 0)) != 0)
+ break;
+ memcpy(&swofs->swofs_datapath_id, &bparam->ifbrp_datapath,
+ sizeof(uint64_t));
+ break;
+ case SIOCSWGFLOWMAX:
+ bparam->ifbrp_maxflow = swofs->swofs_flow_max_entry;
+ break;
+ case SIOCSWGMAXGROUP:
+ bparam->ifbrp_maxgroup = swofs->swofs_group_table_num;
+ break;
+ case SIOCSWSPORTNO:
+ if ((error = suser(curproc, 0)) != 0)
+ break;
+
+ if (breq->ifbr_portno >= OFP_PORT_MAX)
+ return (EINVAL);
+
+ if ((ifs = ifunit(breq->ifbr_ifsname)) == NULL)
+ return (ENOENT);
+
+ if (ifs->if_switchport == NULL)
+ return (ENOENT);
+
+ TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) {
+ if (swpo->swpo_port_no == breq->ifbr_portno)
+ return (EEXIST);
+ }
+
+ swpo = (struct switch_port *)ifs->if_switchport;
+ swpo->swpo_port_no = breq->ifbr_portno;
+
+ break;
default:
error = ENOTTY;
break;
@@ -3161,7 +3205,13 @@ swofp_action_output(struct switch_softc *sc, struct mbuf *m,
/* no support yet */
break;
case OFP_PORT_LOCAL:
- /* no support yet */
+ TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) {
+ if (swpo->swpo_flags & IFBIF_LOCAL) {
+ TAILQ_INSERT_HEAD(&swpld->swpld_fwdp_q, swpo,
+ swpo_fwdp_next);
+ break;
+ }
+ }
break;
default:
TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) {
@@ -5558,7 +5608,10 @@ swofp_mp_recv_port_stats(struct switch_softc *sc, struct mbuf *m)
if (ifs == NULL)
continue;
- postat.pt_port_no = htonl(swpo->swpo_port_no);
+ if (swpo->swpo_flags & IFBIF_LOCAL)
+ postat.pt_port_no = htonl(OFP_PORT_LOCAL);
+ else
+ postat.pt_port_no = htonl(swpo->swpo_port_no);
postat.pt_rx_packets = htobe64(ifs->if_ipackets);
postat.pt_tx_packets = htobe64(ifs->if_opackets);
postat.pt_rx_bytes = htobe64(ifs->if_obytes);
@@ -5888,7 +5941,10 @@ swofp_mp_recv_port_desc(struct switch_softc *sc, struct mbuf *m)
if (ifs == NULL)
continue;
- swp.swp_number = htonl(swpo->swpo_port_no);
+ if (swpo->swpo_flags & IFBIF_LOCAL)
+ swp.swp_number = htonl(OFP_PORT_LOCAL);
+ else
+ swp.swp_number = htonl(swpo->swpo_port_no);
memcpy(swp.swp_macaddr,
((struct arpcom *)ifs)->ac_enaddr, ETHER_ADDR_LEN);
diff --git a/sys/sys/sockio.h b/sys/sys/sockio.h
index 6ccf4e62b71..28202860775 100644
--- a/sys/sys/sockio.h
+++ b/sys/sys/sockio.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sockio.h,v 1.67 2016/08/28 07:22:11 reyk Exp $ */
+/* $OpenBSD: sockio.h,v 1.68 2016/09/02 10:01:36 goda Exp $ */
/* $NetBSD: sockio.h,v 1.5 1995/08/23 00:40:47 thorpej Exp $ */
/*-
@@ -102,6 +102,7 @@
#define SIOCBRDGGTO _IOWR('i', 70, struct ifbrparam)/* cache timeout */
#define SIOCBRDGDADDR _IOW('i', 71, struct ifbareq) /* delete addr */
#define SIOCBRDGFLUSH _IOW('i', 72, struct ifbreq) /* flush addr cache */
+#define SIOCBRDGADDL _IOW('i', 73, struct ifbreq) /* add local port */
#define SIOCBRDGARL _IOW('i', 77, struct ifbrlreq) /* add bridge rule */
#define SIOCBRDGFRL _IOW('i', 78, struct ifbrlreq) /* flush brdg rules */
@@ -122,6 +123,16 @@
#define SIOCBRDGSPROTO _IOW('i', 90, struct ifbrparam)/* set protocol */
#define SIOCBRDGS
+/* Following ioctls for switch(4) has compatibility to bridge(4) */
+#define SIOCSWSFLOWMAX SIOCBRDGSCACHE /* set max flow per table */
+#define SIOCSWGFLOWMAX SIOCBRDGGCACHE /* get max flow per table */
+
+#define SIOCSWGDPID _IOWR('i', 91, struct ifbrparam)/* set datapath id */
+#define SIOCSWSDPID _IOW('i', 91, struct ifbrparam)/* get datapath id */
+#define SIOCSWGMAXGROUP _IOWR('i', 92, struct ifbrparam)/* get max groups */
+#define SIOCSWSMAXGROUP _IOW('i', 92, struct ifbrparam)/* set max groups */
+#define SIOCSWSPORTNO _IOWR('i', 93, struct ifbreq) /* set port number */
+
#define SIOCSIFMTU _IOW('i', 127, struct ifreq) /* set ifnet mtu */
#define SIOCGIFMTU _IOWR('i', 126, struct ifreq) /* get ifnet mtu */
#define SIOCSIFASYNCMAP _IOW('i', 125, struct ifreq) /* set ppp asyncmap */