From: claudio Date: Thu, 11 Nov 2021 10:03:08 +0000 (+0000) Subject: Retire switch(4) it never really was production ready and the OpenFlow X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=9f9935a8e959ae3912357f67f4fed13f93d4ba9b;p=openbsd Retire switch(4) it never really was production ready and the OpenFlow API implemented is a deadend. OK akoshibe@ yasuoka@ deraadt@ kn@ patrick@ sthen@ --- diff --git a/sys/arch/alpha/alpha/conf.c b/sys/arch/alpha/alpha/conf.c index d3f2667e1ab..61f25eafe28 100644 --- a/sys/arch/alpha/alpha/conf.c +++ b/sys/arch/alpha/alpha/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.89 2021/01/23 05:08:34 thfr Exp $ */ +/* $OpenBSD: conf.c,v 1.90 2021/11/11 10:03:08 claudio Exp $ */ /* $NetBSD: conf.c,v 1.16 1996/10/18 21:26:57 cgd Exp $ */ /*- @@ -128,7 +128,6 @@ cdev_decl(pci); #include "vscsi.h" #include "pppx.h" #include "fuse.h" -#include "switch.h" struct cdevsw cdevsw[] = { @@ -205,7 +204,7 @@ struct cdevsw cdevsw[] = cdev_notdef(), /* 66: was USB scanners */ cdev_fuse_init(NFUSE,fuse), /* 67: fuse */ cdev_tun_init(NTUN,tap), /* 68: Ethernet network tunnel */ - cdev_switch_init(NSWITCH,switch), /* 69: switch(4) control interface */ + cdev_notdef(), /* 69: was switch(4) */ cdev_fido_init(NFIDO,fido), /* 70: FIDO/U2F security key */ cdev_pppx_init(NPPPX,pppac), /* 71: PPP Access Concentrator */ cdev_ujoy_init(NUJOY,ujoy), /* 72: USB joystick/gamecontroller */ diff --git a/sys/arch/amd64/amd64/conf.c b/sys/arch/amd64/amd64/conf.c index 3005c0b8a3b..d4d95ae5caa 100644 --- a/sys/arch/amd64/amd64/conf.c +++ b/sys/arch/amd64/amd64/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.73 2021/01/23 05:08:34 thfr Exp $ */ +/* $OpenBSD: conf.c,v 1.74 2021/11/11 10:03:08 claudio Exp $ */ /* * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. @@ -173,7 +173,6 @@ cdev_decl(pci); #include "fuse.h" #include "pvbus.h" #include "ipmi.h" -#include "switch.h" struct cdevsw cdevsw[] = { @@ -286,7 +285,7 @@ struct cdevsw cdevsw[] = cdev_tty_init(NVIOCON,viocon), /* 94: virtio console */ cdev_pvbus_init(NPVBUS,pvbus), /* 95: pvbus(4) control interface */ cdev_ipmi_init(NIPMI,ipmi), /* 96: ipmi */ - cdev_switch_init(NSWITCH,switch), /* 97: switch(4) control interface */ + cdev_notdef(), /* 97: was switch(4) */ cdev_fido_init(NFIDO,fido), /* 98: FIDO/U2F security keys */ cdev_pppx_init(NPPPX,pppac), /* 99: PPP Access Concentrator */ cdev_ujoy_init(NUJOY,ujoy), /* 100: USB joystick/gamecontroller */ diff --git a/sys/arch/arm/arm/conf.c b/sys/arch/arm/arm/conf.c index 2cc3dfce479..a97a2092ed3 100644 --- a/sys/arch/arm/arm/conf.c +++ b/sys/arch/arm/arm/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.57 2021/03/25 04:12:00 jsg Exp $ */ +/* $OpenBSD: conf.c,v 1.58 2021/11/11 10:03:08 claudio Exp $ */ /* $NetBSD: conf.c,v 1.10 2002/04/19 01:04:38 wiz Exp $ */ /* @@ -264,8 +264,6 @@ struct bdevsw bdevsw[] = { #define NSPKR 0 #endif -#include "switch.h" - struct cdevsw cdevsw[] = { cdev_cn_init(1,cn), /* 0: virtual console */ cdev_ctty_init(1,ctty), /* 1: controlling terminal */ @@ -376,7 +374,7 @@ struct cdevsw cdevsw[] = { cdev_disk_init(1,diskmap), /* 102: disk mapper */ cdev_pppx_init(NPPPX,pppx), /* 103: pppx */ cdev_tun_init(NTUN,tap), /* 104: Ethernet tap */ - cdev_switch_init(NSWITCH,switch), /* 105: switch(4) control interface */ + cdev_notdef(), /* 105: was switch(4) */ cdev_fido_init(NFIDO,fido), /* 106: FIDO/U2F security key */ cdev_pppx_init(NPPPX,pppac), /* 107: PPP Access Concentrator */ cdev_ujoy_init(NUJOY,ujoy), /* 108: USB joystick/gamecontroller */ diff --git a/sys/arch/arm64/arm64/conf.c b/sys/arch/arm64/arm64/conf.c index a47ca8313d5..543b8241dda 100644 --- a/sys/arch/arm64/arm64/conf.c +++ b/sys/arch/arm64/arm64/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.18 2021/04/26 06:05:55 jsg Exp $ */ +/* $OpenBSD: conf.c,v 1.19 2021/11/11 10:03:08 claudio Exp $ */ /* * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. @@ -121,7 +121,6 @@ cdev_decl(pci); #include "openprom.h" #include "gpio.h" #include "ipmi.h" -#include "switch.h" struct cdevsw cdevsw[] = { @@ -230,7 +229,7 @@ struct cdevsw cdevsw[] = cdev_notdef(), /* 94 */ cdev_notdef(), /* 95 */ cdev_ipmi_init(NIPMI,ipmi), /* 96: ipmi */ - cdev_switch_init(NSWITCH,switch), /* 97: switch(4) control interface */ + cdev_notdef(), /* 97: was switch(4) */ cdev_fido_init(NFIDO,fido), /* 98: FIDO/U2F security key */ cdev_pppx_init(NPPPX,pppac), /* 99: PPP Access Concentrator */ cdev_ujoy_init(NUJOY,ujoy), /* 100: USB joystick/gamecontroller */ diff --git a/sys/arch/hppa/hppa/conf.c b/sys/arch/hppa/hppa/conf.c index 4d7a12bac26..a3cb39e00cc 100644 --- a/sys/arch/hppa/hppa/conf.c +++ b/sys/arch/hppa/hppa/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.71 2021/01/23 05:08:35 thfr Exp $ */ +/* $OpenBSD: conf.c,v 1.72 2021/11/11 10:03:09 claudio Exp $ */ /*- * Copyright (c) 1991 The Regents of the University of California. @@ -120,7 +120,6 @@ cdev_decl(pci); #include "ucom.h" #include "fuse.h" -#include "switch.h" struct cdevsw cdevsw[] = { @@ -189,7 +188,7 @@ struct cdevsw cdevsw[] = cdev_pppx_init(NPPPX,pppx), /* 57: pppx */ cdev_fuse_init(NFUSE,fuse), /* 58: fuse */ cdev_tun_init(NTUN,tap), /* 59: Ethernet network tunnel */ - cdev_switch_init(NSWITCH,switch), /* 60: switch(4) control interface */ + cdev_notdef(), /* 60: was switch(4) */ cdev_fido_init(NFIDO,fido), /* 61: FIDO/U2F security key */ cdev_pppx_init(NPPPX,pppac), /* 62: PPP Access Concentrator */ cdev_ujoy_init(NUJOY,ujoy), /* 63: USB joystick/gamecontroller */ diff --git a/sys/arch/i386/i386/conf.c b/sys/arch/i386/i386/conf.c index 788792c4fa2..f99fef71cf1 100644 --- a/sys/arch/i386/i386/conf.c +++ b/sys/arch/i386/i386/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.171 2021/01/23 05:08:35 thfr Exp $ */ +/* $OpenBSD: conf.c,v 1.172 2021/11/11 10:03:09 claudio Exp $ */ /* $NetBSD: conf.c,v 1.75 1996/05/03 19:40:20 christos Exp $ */ /* @@ -173,7 +173,6 @@ cdev_decl(pci); #include "fuse.h" #include "pvbus.h" #include "ipmi.h" -#include "switch.h" struct cdevsw cdevsw[] = { @@ -286,7 +285,7 @@ struct cdevsw cdevsw[] = cdev_tun_init(NTUN,tap), /* 94: Ethernet network tunnel */ cdev_pvbus_init(NPVBUS,pvbus), /* 95: pvbus(4) control interface */ cdev_ipmi_init(NIPMI,ipmi), /* 96: ipmi */ - cdev_switch_init(NSWITCH,switch), /* 97: switch(4) control interface */ + cdev_notdef(), /* 97: was switch(4) */ cdev_fido_init(NFIDO,fido), /* 98: FIDO/U2F security key */ cdev_pppx_init(NPPPX,pppac), /* 99: PPP Access Concentrator */ cdev_ujoy_init(NUJOY,ujoy), /* 100: USB joystick/gamecontroller */ diff --git a/sys/arch/landisk/landisk/conf.c b/sys/arch/landisk/landisk/conf.c index 45cfbd31e32..1ceb054ba1e 100644 --- a/sys/arch/landisk/landisk/conf.c +++ b/sys/arch/landisk/landisk/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.43 2021/01/23 05:08:35 thfr Exp $ */ +/* $OpenBSD: conf.c,v 1.44 2021/11/11 10:03:09 claudio Exp $ */ /* * Copyright (c) 1994-1998 Mark Brinicombe. @@ -243,7 +243,6 @@ struct bdevsw bdevsw[] = { #include "vscsi.h" #include "pppx.h" #include "fuse.h" -#include "switch.h" struct cdevsw cdevsw[] = { cdev_cn_init(1,cn), /* 0: virtual console */ @@ -355,7 +354,7 @@ struct cdevsw cdevsw[] = { cdev_pppx_init(NPPPX,pppx), /* 102: pppx */ cdev_fuse_init(NFUSE,fuse), /* 103: fuse */ cdev_tun_init(NTUN,tap), /* 104: Ethernet network tap */ - cdev_switch_init(NSWITCH,switch), /* 105: switch(4) control interface */ + cdev_notdef(), /* 105: was switch(4) */ cdev_fido_init(NFIDO,fido), /* 106: FIDO/U2F security key */ cdev_pppx_init(NPPPX,pppac), /* 107: PPP Access Concentrator */ cdev_ujoy_init(NUJOY,ujoy), /* 108: USB joystick/gamecontroller */ diff --git a/sys/arch/loongson/loongson/conf.c b/sys/arch/loongson/loongson/conf.c index 0520e67cac1..3b939aee0cb 100644 --- a/sys/arch/loongson/loongson/conf.c +++ b/sys/arch/loongson/loongson/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.30 2021/01/23 05:08:35 thfr Exp $ */ +/* $OpenBSD: conf.c,v 1.31 2021/11/11 10:03:09 claudio Exp $ */ /* * Copyright (c) 1992, 1993 @@ -131,7 +131,6 @@ cdev_decl(pci); #include "vscsi.h" #include "pppx.h" #include "fuse.h" -#include "switch.h" struct cdevsw cdevsw[] = { @@ -214,7 +213,7 @@ struct cdevsw cdevsw[] = cdev_notdef(), /* 72: was USB scanners */ cdev_fuse_init(NFUSE,fuse), /* 73: fuse */ cdev_tun_init(NTUN,tap), /* 74: Ethernet network tunnel */ - cdev_switch_init(NSWITCH,switch), /* 75: switch(4) control interface */ + cdev_notdef(), /* 75: was switch(4) */ cdev_notdef(), /* 76 */ cdev_notdef(), /* 77 */ cdev_notdef(), /* 78 */ diff --git a/sys/arch/luna88k/luna88k/conf.c b/sys/arch/luna88k/luna88k/conf.c index d10b67de9e7..d496ea3ebda 100644 --- a/sys/arch/luna88k/luna88k/conf.c +++ b/sys/arch/luna88k/luna88k/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.34 2020/07/06 04:32:25 dlg Exp $ */ +/* $OpenBSD: conf.c,v 1.35 2021/11/11 10:03:09 claudio Exp $ */ /*- * Copyright (c) 1991 The Regents of the University of California. @@ -73,7 +73,6 @@ #include "vscsi.h" #include "pppx.h" #include "fuse.h" -#include "switch.h" struct bdevsw bdevsw[] = { @@ -160,7 +159,7 @@ struct cdevsw cdevsw[] = cdev_disk_init(1,diskmap), /* 54: disk mapper */ cdev_pppx_init(NPPPX,pppx), /* 55: pppx */ cdev_tun_init(NTUN,tap), /* 56: Ethernet network tunnel */ - cdev_switch_init(NSWITCH,switch), /* 57: switch(4) control interface */ + cdev_notdef(), /* 57: was switch(4) */ cdev_pppx_init(NPPPX,pppac), /* 58: PPP Access Concentrator */ }; int nchrdev = nitems(cdevsw); diff --git a/sys/arch/macppc/macppc/conf.c b/sys/arch/macppc/macppc/conf.c index 6a67a394fe4..e28e9cc911a 100644 --- a/sys/arch/macppc/macppc/conf.c +++ b/sys/arch/macppc/macppc/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.73 2021/01/23 05:08:35 thfr Exp $ */ +/* $OpenBSD: conf.c,v 1.74 2021/11/11 10:03:09 claudio Exp $ */ /* * Copyright (c) 1997 Per Fogelstrom @@ -129,7 +129,6 @@ cdev_decl(pci); #include "vscsi.h" #include "pppx.h" #include "fuse.h" -#include "switch.h" struct cdevsw cdevsw[] = { cdev_cn_init(1,cn), /* 0: virtual console */ @@ -229,7 +228,7 @@ struct cdevsw cdevsw[] = { cdev_tun_init(NTUN,tap), /* 86: Ethernet network tunnel */ cdev_drm_init(NDRM,drm), /* 87: drm */ cdev_fuse_init(NFUSE,fuse), /* 88: fuse */ - cdev_switch_init(NSWITCH,switch), /* 89: switch(4) control interface */ + cdev_notdef(), /* 89: was switch(4) */ cdev_fido_init(NFIDO,fido), /* 90: FIDO/U2F security key */ cdev_pppx_init(NPPPX,pppac), /* 91: PPP Access Concentrator */ cdev_ujoy_init(NUJOY,ujoy), /* 92: USB joystick/gamecontroller */ diff --git a/sys/arch/octeon/octeon/conf.c b/sys/arch/octeon/octeon/conf.c index b8a40b0ea08..d3dc9d1b88e 100644 --- a/sys/arch/octeon/octeon/conf.c +++ b/sys/arch/octeon/octeon/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.26 2021/01/23 05:08:36 thfr Exp $ */ +/* $OpenBSD: conf.c,v 1.27 2021/11/11 10:03:09 claudio Exp $ */ /* * Copyright (c) 1992, 1993 @@ -146,7 +146,6 @@ cdev_decl(pci); #include "fuse.h" #include "octboot.h" #include "openprom.h" -#include "switch.h" struct cdevsw cdevsw[] = { @@ -233,7 +232,7 @@ struct cdevsw cdevsw[] = cdev_notdef(), /* 72: was USB scanners */ cdev_notdef(), /* 73: fuse on other mips64 */ cdev_tun_init(NTUN,tap), /* 74: Ethernet network tunnel */ - cdev_switch_init(NSWITCH,switch), /* 75: switch(4) control interface */ + cdev_notdef(), /* 75: was switch(4) */ cdev_fido_init(NFIDO,fido), /* 76: FIDO/U2F security key */ cdev_pppx_init(NPPPX,pppac), /* 77: PPP Access Concentrator */ cdev_ujoy_init(NUJOY,ujoy), /* 78: USB joystick/gamecontroller */ diff --git a/sys/arch/powerpc64/powerpc64/conf.c b/sys/arch/powerpc64/powerpc64/conf.c index 7d2a989cba5..bda9235be25 100644 --- a/sys/arch/powerpc64/powerpc64/conf.c +++ b/sys/arch/powerpc64/powerpc64/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.12 2021/10/05 04:55:53 deraadt Exp $ */ +/* $OpenBSD: conf.c,v 1.13 2021/11/11 10:03:09 claudio Exp $ */ /*- * Copyright (c) 1991 The Regents of the University of California. @@ -86,7 +86,6 @@ cdev_decl(lpt); #include "pty.h" #include "radio.h" #include "st.h" -#include "switch.h" #include "tun.h" #include "ucom.h" #include "ugen.h" @@ -184,7 +183,7 @@ struct cdevsw cdevsw[] = cdev_notdef(), /* 71 */ cdev_pppx_init(NPPPX,pppx), /* 72: pppx */ cdev_pppx_init(NPPPX,pppac), /* 73: PPP Access Concentrator */ - cdev_switch_init(NSWITCH,switch), /* 74: switch(4) control interface */ + cdev_notdef(), /* 74: was switch(4) */ cdev_tun_init(NTUN,tap), /* 75: Ethernet network tunnel */ cdev_tun_init(NTUN,tun), /* 76: network tunnel */ cdev_notdef(), /* 77 */ diff --git a/sys/arch/riscv64/riscv64/conf.c b/sys/arch/riscv64/riscv64/conf.c index bdebadc79e0..27618a6deb4 100644 --- a/sys/arch/riscv64/riscv64/conf.c +++ b/sys/arch/riscv64/riscv64/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.11 2021/10/05 18:32:28 deraadt Exp $ */ +/* $OpenBSD: conf.c,v 1.12 2021/11/11 10:03:09 claudio Exp $ */ /* * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. @@ -110,7 +110,6 @@ cdev_decl(pci); #include "fuse.h" #include "openprom.h" #include "ipmi.h" -#include "switch.h" struct cdevsw cdevsw[] = { @@ -219,7 +218,7 @@ struct cdevsw cdevsw[] = cdev_notdef(), /* 94 */ cdev_notdef(), /* 95 */ cdev_ipmi_init(NIPMI,ipmi), /* 96: ipmi */ - cdev_switch_init(NSWITCH,switch), /* 97: switch(4) control interface */ + cdev_notdef(), /* 97: was switch(4) */ cdev_notdef(), /* 98: FIDO/U2F security key */ cdev_pppx_init(NPPPX,pppac), /* 99: PPP Access Concentrator */ cdev_notdef(), /* 100: USB joystick/gamecontroller */ diff --git a/sys/arch/sparc64/sparc64/conf.c b/sys/arch/sparc64/sparc64/conf.c index 6e7df9247dd..9c5b692f24e 100644 --- a/sys/arch/sparc64/sparc64/conf.c +++ b/sys/arch/sparc64/sparc64/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.85 2021/01/23 05:08:36 thfr Exp $ */ +/* $OpenBSD: conf.c,v 1.86 2021/11/11 10:03:09 claudio Exp $ */ /* $NetBSD: conf.c,v 1.17 2001/03/26 12:33:26 lukem Exp $ */ /* @@ -119,7 +119,6 @@ cdev_decl(pci); #include "vscsi.h" #include "pppx.h" #include "fuse.h" -#include "switch.h" struct bdevsw bdevsw[] = { @@ -295,7 +294,7 @@ struct cdevsw cdevsw[] = cdev_vdsp_init(NVDSP,vdsp), /* 133: vdsp */ cdev_fuse_init(NFUSE,fuse), /* 134: fuse */ cdev_tun_init(NTUN,tap), /* 135: Ethernet network tunnel */ - cdev_switch_init(NSWITCH,switch), /* 136: switch(4) control interface */ + cdev_notdef(), /* 136: was switch(4) */ cdev_fido_init(NFIDO,fido), /* 137: FIDO/U2F security key */ cdev_pppx_init(NPPPX,pppac), /* 138: PPP Access Concentrator */ cdev_ujoy_init(NUJOY,ujoy), /* 139: USB joystick/gamecontroller */ diff --git a/sys/conf/GENERIC b/sys/conf/GENERIC index 71db3057946..33326a3a830 100644 --- a/sys/conf/GENERIC +++ b/sys/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.279 2021/09/22 18:24:04 benno Exp $ +# $OpenBSD: GENERIC,v 1.280 2021/11/11 10:03:10 claudio Exp $ # # Machine-independent option; used by all architectures for their # GENERIC kernel @@ -108,7 +108,6 @@ pseudo-device tun # network tunneling over tty (tun & tap) pseudo-device vether # Virtual ethernet pseudo-device vxlan # Virtual extensible LAN pseudo-device vlan # IEEE 802.1Q VLAN -pseudo-device switch # Switch pseudo-device wg # WireGuard pseudo-device bio 1 # ioctl multiplexing device diff --git a/sys/conf/files b/sys/conf/files index b69d1d7b0fd..b33c8443167 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $OpenBSD: files,v 1.705 2021/11/08 14:52:08 stsp Exp $ +# $OpenBSD: files,v 1.706 2021/11/11 10:03:10 claudio Exp $ # $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 @@ -577,7 +577,6 @@ pseudo-device bpe: ifnet, ether, ifmedia, etherbridge pseudo-device vether: ifnet, ether pseudo-device pppx: ifnet pseudo-device vxlan: ifnet, ether, ifmedia -pseudo-device switch: ifnet, ether pseudo-device wg: ifnet pseudo-device ksyms @@ -822,9 +821,6 @@ file net/bridgestp.c bridge file net/if_etherbridge.c etherbridge file net/if_veb.c veb file net/if_vlan.c vlan needs-count -file net/if_switch.c switch needs-count -file net/switchctl.c switch -file net/switchofp.c switch file net/pipex.c pipex file net/radix.c pf | ipsec | pipex | nfsserver file net/rtable.c diff --git a/sys/net/if.c b/sys/net/if.c index 8fe99eff4df..2e9a968d7cc 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if.c,v 1.643 2021/07/20 16:32:28 bluhm Exp $ */ +/* $OpenBSD: if.c,v 1.644 2021/11/11 10:03:10 claudio Exp $ */ /* $NetBSD: if.c,v 1.35 1996/05/07 05:26:04 thorpej Exp $ */ /* @@ -68,7 +68,6 @@ #include "pf.h" #include "pfsync.h" #include "ppp.h" -#include "switch.h" #include "if_wg.h" #include @@ -911,13 +910,6 @@ if_netisr(void *unused) #if NBRIDGE > 0 if (n & (1 << NETISR_BRIDGE)) bridgeintr(); -#endif -#if NSWITCH > 0 - if (n & (1 << NETISR_SWITCH)) { - KERNEL_LOCK(); - switchintr(); - KERNEL_UNLOCK(); - } #endif t |= n; } @@ -2260,7 +2252,6 @@ forceup: case SIOCBRDGSIFCOST: case SIOCBRDGSTXHC: case SIOCBRDGSPROTO: - case SIOCSWSPORTNO: #endif if ((error = suser(p)) != 0) break; diff --git a/sys/net/if_bridge.h b/sys/net/if_bridge.h index ed384bed9f1..6fa74c878ad 100644 --- a/sys/net/if_bridge.h +++ b/sys/net/if_bridge.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_bridge.h,v 1.72 2021/03/10 10:21:47 jsg Exp $ */ +/* $OpenBSD: if_bridge.h,v 1.73 2021/11/11 10:03:10 claudio Exp $ */ /* * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net) @@ -155,8 +155,6 @@ 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 @@ -167,9 +165,6 @@ 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 diff --git a/sys/net/if_switch.c b/sys/net/if_switch.c deleted file mode 100644 index 43449a745f2..00000000000 --- a/sys/net/if_switch.c +++ /dev/null @@ -1,1589 +0,0 @@ -/* $OpenBSD: if_switch.c,v 1.44 2021/07/07 20:19:01 sashan Exp $ */ - -/* - * Copyright (c) 2016 Kazuya GODA - * Copyright (c) 2016 Reyk Floeter - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "bpfilter.h" -#include "pf.h" -#include "vlan.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if NPF > 0 -#include -#endif - -#if NBPFILTER > 0 -#include -#endif - -#include -#include -#include - -int switch_clone_create(struct if_clone *, int); -int switch_clone_destroy(struct ifnet *); -void switch_process(struct ifnet *, struct mbuf *); -int switch_port_set_local(struct switch_softc *, struct switch_port *); -int switch_port_unset_local(struct switch_softc *, struct switch_port *); -int switch_ioctl(struct ifnet *, unsigned long, caddr_t); -int switch_port_add(struct switch_softc *, struct ifbreq *); -void switch_port_detach(void *); -int switch_port_del(struct switch_softc *, struct ifbreq *); -int switch_port_list(struct switch_softc *, struct ifbifconf *); -struct mbuf * - switch_input(struct ifnet *, struct mbuf *, uint64_t, void *); -struct mbuf - *switch_port_ingress(struct switch_softc *, struct ifnet *, - struct mbuf *); -int switch_ifenqueue(struct switch_softc *, struct ifnet *, - struct mbuf *, int); -void switch_port_ifb_start(struct ifnet *); - -struct mbuf - *switch_flow_classifier_udp(struct mbuf *, int *, - struct switch_flow_classify *); -struct mbuf - *switch_flow_classifier_tcp(struct mbuf *, int *, - struct switch_flow_classify *); -struct mbuf - *switch_flow_classifier_icmpv4(struct mbuf *, int *, - struct switch_flow_classify *); -struct mbuf - *switch_flow_classifier_nd6(struct mbuf *, int *, - struct switch_flow_classify *); -struct mbuf - *switch_flow_classifier_icmpv6(struct mbuf *, int *, - struct switch_flow_classify *); -struct mbuf - *switch_flow_classifier_ipv4(struct mbuf *, int *, - struct switch_flow_classify *); -struct mbuf - *switch_flow_classifier_ipv6(struct mbuf *, int *, - struct switch_flow_classify *); -struct mbuf - *switch_flow_classifier_arp(struct mbuf *, int *, - struct switch_flow_classify *); -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 *); -void switch_flow_classifier_dump(struct switch_softc *, - struct switch_flow_classify *); -void switchattach(int); -void switch_take(void *); -void switch_rele(void *); - -struct if_clone switch_cloner = - IF_CLONE_INITIALIZER("switch", switch_clone_create, switch_clone_destroy); - -LIST_HEAD(, switch_softc) switch_list; -struct niqueue switchintrq = NIQUEUE_INITIALIZER(1024, NETISR_SWITCH); -struct rwlock switch_ifs_lk = RWLOCK_INITIALIZER("switchifs"); - -struct pool swfcl_pool; - -const struct ether_brport switch_brport = { - switch_input, - switch_take, - switch_rele, - NULL, -}; - -void -switchattach(int n) -{ - pool_init(&swfcl_pool, sizeof(union switch_field), 0, 0, 0, - "swfcl", NULL); - swofp_attach(); - LIST_INIT(&switch_list); - if_clone_attach(&switch_cloner); -} - -struct switch_softc * -switch_lookup(int unit) -{ - struct switch_softc *sc; - - /* must hold switch_ifs_lk */ - LIST_FOREACH(sc, &switch_list, sc_switch_next) { - if (sc->sc_unit == unit) - return (sc); - } - - return (NULL); -} - -int -switch_clone_create(struct if_clone *ifc, int unit) -{ - struct switch_softc *sc; - struct ifnet *ifp; - - sc = malloc(sizeof(struct switch_softc), M_DEVBUF, M_WAITOK|M_ZERO); - ifp = &sc->sc_if; - snprintf(ifp->if_xname, sizeof ifp->if_xname, "switch%d", unit); - ifp->if_softc = sc; - ifp->if_mtu = ETHERMTU; - ifp->if_ioctl = switch_ioctl; - ifp->if_output = NULL; - ifp->if_start = NULL; - ifp->if_type = IFT_BRIDGE; - ifp->if_hdrlen = ETHER_HDR_LEN; - ifp->if_xflags = IFXF_CLONED; - TAILQ_INIT(&sc->sc_swpo_list); - - sc->sc_unit = unit; - sc->sc_stp = bstp_create(); - if (!sc->sc_stp) { - free(sc, M_DEVBUF, sizeof(*sc)); - return (ENOMEM); - } - - if_attach(ifp); - if_alloc_sadl(ifp); - -#if NBPFILTER > 0 - bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, ETHER_HDR_LEN); -#endif - - swofp_create(sc); - - LIST_INSERT_HEAD(&switch_list, sc, sc_switch_next); - - return (0); -} - -int -switch_clone_destroy(struct ifnet *ifp) -{ - struct switch_softc *sc = ifp->if_softc; - struct switch_port *swpo, *tp; - struct ifnet *ifs; - - NET_LOCK(); - TAILQ_FOREACH_SAFE(swpo, &sc->sc_swpo_list, swpo_list_next, tp) { - if ((ifs = if_get(swpo->swpo_ifindex)) != NULL) { - switch_port_detach(ifs); - if_put(ifs); - } else - log(LOG_ERR, "failed to cleanup on ifindex(%d)\n", - swpo->swpo_ifindex); - } - NET_UNLOCK(); - LIST_REMOVE(sc, sc_switch_next); - bstp_destroy(sc->sc_stp); - swofp_destroy(sc); - switch_dev_destroy(sc); - if_detach(ifp); - free(sc, M_DEVBUF, sizeof(*sc)); - - return (0); -} - - -void -switchintr(void) -{ - struct mbuf_list ml; - struct mbuf *m; - struct ifnet *ifp; - - niq_delist(&switchintrq, &ml); - if (ml_empty(&ml)) - return; - - while ((m = ml_dequeue(&ml)) != NULL) { - KASSERT(m->m_flags & M_PKTHDR); - ifp = if_get(m->m_pkthdr.ph_ifidx); - if (ifp == NULL) { - m_freem(m); - continue; - } - switch_process(ifp, m); - if_put(ifp); - } - -} - -void -switch_process(struct ifnet *ifp, struct mbuf *m) -{ - struct switch_softc *sc = NULL; - struct switch_port *swpo; - struct switch_flow_classify swfcl = { 0 }; - - swpo = (struct switch_port *)ifp->if_switchport; - if (swpo == NULL) - goto discard; - sc = swpo->swpo_switch; - if ((sc->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) - goto discard; - -#if NBPFILTER > 0 - if (sc->sc_if.if_bpf) - bpf_mtap_ether(sc->sc_if.if_bpf, m, BPF_DIRECTION_IN); -#endif - - if (m->m_pkthdr.len < sizeof(struct ether_header)) - goto discard; - - if ((m = switch_port_ingress(sc, ifp, m)) == NULL) - return; /* m was freed in switch_process_ingress */ - - if ((m = switch_flow_classifier(m, swpo->swpo_port_no, - &swfcl)) == NULL) { - switch_swfcl_free(&swfcl); - return; /* m was freed in switch_flow_classifier */ - } - - if (sc->sc_if.if_flags & IFF_DEBUG) - switch_flow_classifier_dump(sc, &swfcl); - - if (!sc->switch_process_forward) - goto discard; - - (sc->switch_process_forward)(sc, &swfcl, m); - - switch_swfcl_free(&swfcl); - return; - -discard: - m_freem(m); - switch_swfcl_free(&swfcl); - if (sc) - sc->sc_if.if_oerrors++; -} - -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; - struct ifbropreq *brop = (struct ifbropreq *)data; - struct ifbrlconf *bc = (struct ifbrlconf *)data; - struct ifbreq *breq = (struct ifbreq *)data; - struct switch_softc *sc = ifp->if_softc; - struct bstp_state *bs = sc->sc_stp; - struct bstp_port *bp; - struct ifnet *ifs; - struct switch_port *swpo; - int error = 0; - - switch (cmd) { - case SIOCBRDGADD: - if ((error = suser(curproc)) != 0) - break; - error = switch_port_add(sc, (struct ifbreq *)data); - break; - case SIOCBRDGDEL: - if ((error = suser(curproc)) != 0) - break; - error = switch_port_del(sc, (struct ifbreq *)data); - break; - case SIOCBRDGIFS: - error = switch_port_list(sc, (struct ifbifconf *)data); - break; - case SIOCBRDGADDL: - if ((error = suser(curproc)) != 0) - break; - error = switch_port_add(sc, (struct ifbreq *)data); - if (error && error != EEXIST) - break; - ifs = if_unit(breq->ifbr_ifsname); - if (ifs == NULL) { - error = ENOENT; - break; - } - swpo = (struct switch_port *)ifs->if_switchport; - if_put(ifs); - if (swpo == NULL || swpo->swpo_switch != sc) { - error = ESRCH; - break; - } - error = switch_port_set_local(sc, swpo); - break; - case SIOCBRDGGIFFLGS: - ifs = if_unit(breq->ifbr_ifsname); - if (ifs == NULL) { - error = ENOENT; - break; - } - swpo = (struct switch_port *)ifs->if_switchport; - if_put(ifs); - if (swpo == NULL || swpo->swpo_switch != sc) { - error = ESRCH; - break; - } - breq->ifbr_ifsflags = swpo->swpo_flags; - breq->ifbr_portno = swpo->swpo_port_no; - breq->ifbr_protected = swpo->swpo_protected; - break; - case SIOCSIFFLAGS: - if ((ifp->if_flags & IFF_UP) == IFF_UP) { - if ((ifp->if_flags & IFF_RUNNING) == 0) { - ifp->if_flags |= IFF_RUNNING; - bstp_enable(sc->sc_stp, ifp->if_index); - } - } - - if ((ifp->if_flags & IFF_UP) == 0) { - if ((ifp->if_flags & IFF_RUNNING) == IFF_RUNNING) { - ifp->if_flags &= ~IFF_RUNNING; - bstp_disable(sc->sc_stp); - } - } - - break; - case SIOCBRDGRTS: - baconf->ifbac_len = 0; - break; - case SIOCBRDGGRL: - bc->ifbrl_len = 0; - break; - case SIOCBRDGGPARAM: - if ((bp = bs->bs_root_port) == NULL) - brop->ifbop_root_port = 0; - else - brop->ifbop_root_port = bp->bp_ifindex; - brop->ifbop_maxage = bs->bs_bridge_max_age >> 8; - brop->ifbop_hellotime = bs->bs_bridge_htime >> 8; - brop->ifbop_fwddelay = bs->bs_bridge_fdelay >> 8; - brop->ifbop_holdcount = bs->bs_txholdcount; - brop->ifbop_priority = bs->bs_bridge_priority; - brop->ifbop_protocol = bs->bs_protover; - brop->ifbop_root_bridge = bs->bs_root_pv.pv_root_id; - brop->ifbop_root_path_cost = bs->bs_root_pv.pv_cost; - brop->ifbop_root_port = bs->bs_root_pv.pv_port_id; - brop->ifbop_desg_bridge = bs->bs_root_pv.pv_dbridge_id; - 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 SIOCBRDGSIFPROT: - ifs = if_unit(breq->ifbr_ifsname); - if (ifs == NULL) { - error = ENOENT; - break; - } - swpo = (struct switch_port *)ifs->if_switchport; - if_put(ifs); - if (swpo == NULL || swpo->swpo_switch != sc) { - error = ESRCH; - break; - } - swpo->swpo_protected = breq->ifbr_protected; - break; - case SIOCSWGDPID: - case SIOCSWSDPID: - case SIOCSWGMAXFLOW: - case SIOCSWGMAXGROUP: - case SIOCSWSPORTNO: - error = swofp_ioctl(ifp, cmd, data); - break; - default: - error = ENOTTY; - break; - } - - return (error); -} - -int -switch_port_add(struct switch_softc *sc, struct ifbreq *req) -{ - struct ifnet *ifs; - struct switch_port *swpo; - int error; - - if ((ifs = if_unit(req->ifbr_ifsname)) == NULL) - return (ENOENT); - - if (ifs->if_type != IFT_ETHER) { - error = EPROTONOSUPPORT; - goto put; - } - - if (ifs->if_switchport != NULL) { - swpo = (struct switch_port *)ifs->if_switchport; - if (swpo->swpo_switch == sc) - error = EEXIST; - else - error = EBUSY; - - goto put; - } - - if ((error = ifpromisc(ifs, 1)) != 0) - goto put; - - if ((error = ether_brport_isset(ifs)) != 0) - goto unset; - - swpo = malloc(sizeof(*swpo), M_DEVBUF, M_NOWAIT|M_ZERO); - if (swpo == NULL) { - error = ENOMEM; - goto unset; - } - - swpo->swpo_switch = sc; - swpo->swpo_ifindex = ifs->if_index; - ifs->if_switchport = (caddr_t)swpo; - ether_brport_set(ifs, &switch_brport); - swpo->swpo_port_no = swofp_assign_portno(sc, ifs->if_index); - task_set(&swpo->swpo_dtask, switch_port_detach, ifs); - if_detachhook_add(ifs, &swpo->swpo_dtask); - if_put(ifs); - - nanouptime(&swpo->swpo_appended); - - TAILQ_INSERT_TAIL(&sc->sc_swpo_list, swpo, swpo_list_next); - - return (0); - -unset: - ifpromisc(ifs, 0); -put: - - if_put(ifs); - return (error); -} - -int -switch_port_list(struct switch_softc *sc, struct ifbifconf *bifc) -{ - struct switch_port *swpo; - struct ifnet *ifs; - struct ifbreq breq; - int total = 0, n = 0, error = 0; - - TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) - total++; - - if (bifc->ifbic_len == 0) { - n = total; - goto done; - } - - TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) { - memset(&breq, 0, sizeof(breq)); - - if (bifc->ifbic_len < sizeof(breq)) - break; - - ifs = if_get(swpo->swpo_ifindex); - if (ifs == NULL) { - error = ENOENT; - goto done; - } - strlcpy(breq.ifbr_ifsname, ifs->if_xname, IFNAMSIZ); - if_put(ifs); - - strlcpy(breq.ifbr_name, sc->sc_if.if_xname, IFNAMSIZ); - breq.ifbr_ifsflags = swpo->swpo_flags; - breq.ifbr_portno = swpo->swpo_port_no; - breq.ifbr_protected = swpo->swpo_protected; - if ((error = copyout((caddr_t)&breq, - (caddr_t)(bifc->ifbic_req + n), sizeof(breq))) != 0) - goto done; - - bifc->ifbic_len -= sizeof(breq); - n++; - } - -done: - bifc->ifbic_len = n * sizeof(breq); - return (error); -} - -void -switch_port_detach(void *arg) -{ - struct ifnet *ifp = (struct ifnet *)arg; - struct switch_softc *sc; - struct switch_port *swpo; - - swpo = (struct switch_port *)ifp->if_switchport; - sc = swpo->swpo_switch; - if (swpo->swpo_flags & IFBIF_LOCAL) - switch_port_unset_local(sc, swpo); - - ifp->if_switchport = NULL; - if_detachhook_del(ifp, &swpo->swpo_dtask); - ifpromisc(ifp, 0); - ether_brport_clr(ifp); - TAILQ_REMOVE(&sc->sc_swpo_list, swpo, swpo_list_next); - free(swpo, M_DEVBUF, sizeof(*swpo)); -} - -int -switch_port_del(struct switch_softc *sc, struct ifbreq *req) -{ - struct switch_port *swpo; - struct ifnet *ifs; - int error = 0; - - TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) { - if ((ifs = if_get(swpo->swpo_ifindex)) == NULL) - continue; - if (strncmp(ifs->if_xname, req->ifbr_ifsname, IFNAMSIZ) == 0) - break; - if_put(ifs); - } - - if (swpo) { - switch_port_detach(ifs); - if_put(ifs); - error = 0; - } else - error = ENOENT; - - return (error); -} - -struct mbuf * -switch_input(struct ifnet *ifp, struct mbuf *m, uint64_t dst, void *null) -{ - KASSERT(m->m_flags & M_PKTHDR); - - if (m->m_flags & M_PROTO1) { - m->m_flags &= ~M_PROTO1; - return (m); - } - - niq_enqueue(&switchintrq, m); - - return (NULL); -} - - -struct mbuf * -switch_port_ingress(struct switch_softc *sc, struct ifnet *src_if, - struct mbuf *m) -{ - struct ether_header eh; - - sc->sc_if.if_ipackets++; - sc->sc_if.if_ibytes += m->m_pkthdr.len; - - m_copydata(m, 0, ETHER_HDR_LEN, &eh); -#if 0 - /* It's the "#if 0" because it doesn't test switch(4) with pf(4) - * or with ipsec(4). - */ - if ((m = bridge_ip((struct bridge_softc *)sc, - PF_IN, src_if, &eh, m)) == NULL) { - sc->sc_if.if_ierrors++; - return (NULL); - } -#endif /* NPF */ - - return (m); -} - -void -switch_port_egress(struct switch_softc *sc, struct switch_fwdp_queue *fwdp_q, - struct mbuf *m) -{ - struct switch_port *swpo; - struct ifnet *dst_if; - struct mbuf *mc; - struct ether_header eh; - int len, used = 0; - -#if NBPFILTER > 0 - if (sc->sc_if.if_bpf) - bpf_mtap(sc->sc_if.if_bpf, m, BPF_DIRECTION_OUT); -#endif - - m_copydata(m, 0, ETHER_HDR_LEN, &eh); - TAILQ_FOREACH(swpo, fwdp_q, swpo_fwdp_next) { - - if ((dst_if = if_get(swpo->swpo_ifindex)) == NULL) - continue; - - if ((dst_if->if_flags & IFF_RUNNING) == 0) - goto out; - - if (TAILQ_NEXT(swpo, swpo_fwdp_next) == NULL) { - mc = m; - used = 1; - } else { - mc = m_dup_pkt(m, ETHER_ALIGN, M_NOWAIT); - if (mc == NULL) - goto out; - } - -#if 0 - /* It's the "#if 0" because it doesn't test switch(4) with pf(4) - * or with ipsec(4). - */ - if ((mc = bridge_ip((struct bridge_softc *)sc, - PF_OUT, dst_if, &eh, mc)) == NULL) { - sc->sc_if.if_ierrors++; - goto out; - } -#endif - - len = mc->m_pkthdr.len; -#if NVLAN > 0 - if ((mc->m_flags & M_VLANTAG) && - (dst_if->if_capabilities & IFCAP_VLAN_HWTAGGING) == 0) - len += ETHER_VLAN_ENCAP_LEN; -#endif - - /* - * 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(&sc->sc_if, dst_if, &eh, mc); - else - switch_ifenqueue(sc, dst_if, mc, - (swpo->swpo_flags & IFBIF_LOCAL)); - out: - - if_put(dst_if); - } - - if (!used) - m_freem(m); -} - -int -switch_ifenqueue(struct switch_softc *sc, struct ifnet *ifp, - struct mbuf *m, int local) -{ - struct mbuf_list ml = MBUF_LIST_INITIALIZER(); - int error, len; - - /* Loop prevention. */ - m->m_flags |= M_PROTO1; - - KASSERT(m->m_flags & M_PKTHDR); - len = m->m_pkthdr.len; - - if (local) { - ml_enqueue(&ml, m); - if_input(ifp, &ml); - } else { - error = if_enqueue(ifp, m); - if (error) { - sc->sc_if.if_oerrors++; - return (error); - } - sc->sc_if.if_opackets++; - sc->sc_if.if_obytes += len; - } - - return (0); -} - -void -switch_port_ifb_start(struct ifnet *ifp) -{ - struct mbuf *m; - struct mbuf_list ml = MBUF_LIST_INITIALIZER(); - - for (;;) { - m = ifq_dequeue(&ifp->if_snd); - if (m == NULL) - return; - -#if NBPFILTER > 0 - if (ifp->if_bpf) - bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); -#endif /* NBPFILTER > 0 */ - - ml_enqueue(&ml, m); - if_input(ifp, &ml); - } -} - -/* - * Flow Classifier - */ - -int -switch_swfcl_dup(struct switch_flow_classify *from, - struct switch_flow_classify *to) -{ - memset(to, 0, sizeof(*to)); - - to->swfcl_flow_hash = from->swfcl_flow_hash; - to->swfcl_metadata = from->swfcl_metadata; - to->swfcl_cookie = from->swfcl_cookie; - to->swfcl_table_id = from->swfcl_table_id; - to->swfcl_in_port = from->swfcl_in_port; - - if (from->swfcl_tunnel) { - to->swfcl_tunnel = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO); - if (to->swfcl_tunnel == NULL) - goto failed; - memcpy(to->swfcl_tunnel, from->swfcl_tunnel, - sizeof(*from->swfcl_tunnel)); - } - if (from->swfcl_ether) { - to->swfcl_ether = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO); - if (to->swfcl_ether == NULL) - goto failed; - memcpy(to->swfcl_ether, from->swfcl_ether, - sizeof(*from->swfcl_ether)); - } - if (from->swfcl_vlan) { - to->swfcl_vlan = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO); - if (to->swfcl_vlan == NULL) - goto failed; - memcpy(to->swfcl_vlan, from->swfcl_vlan, - sizeof(*from->swfcl_vlan)); - } - if (from->swfcl_ipv4) { - to->swfcl_ipv4 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO); - if (to->swfcl_ipv4 == NULL) - goto failed; - memcpy(to->swfcl_ipv4, from->swfcl_ipv4, - sizeof(*from->swfcl_ipv4)); - } - if (from->swfcl_ipv6) { - to->swfcl_ipv6 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO); - if (to->swfcl_ipv6 == NULL) - goto failed; - memcpy(to->swfcl_ipv6, from->swfcl_ipv6, - sizeof(*from->swfcl_ipv6)); - } - if (from->swfcl_arp) { - to->swfcl_arp = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO); - if (to->swfcl_arp == NULL) - goto failed; - memcpy(to->swfcl_arp, from->swfcl_arp, - sizeof(*from->swfcl_arp)); - - } - if (from->swfcl_nd6) { - to->swfcl_nd6 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO); - if (to->swfcl_nd6 == NULL) - goto failed; - memcpy(to->swfcl_nd6, from->swfcl_nd6, - sizeof(*from->swfcl_nd6)); - } - if (from->swfcl_icmpv4) { - to->swfcl_icmpv4 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO); - if (to->swfcl_icmpv4 == NULL) - goto failed; - memcpy(to->swfcl_icmpv4, from->swfcl_icmpv4, - sizeof(*from->swfcl_icmpv4)); - } - if (from->swfcl_icmpv6) { - to->swfcl_icmpv6 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO); - if (to->swfcl_icmpv6 == NULL) - goto failed; - memcpy(to->swfcl_icmpv6, from->swfcl_icmpv6, - sizeof(*from->swfcl_icmpv6)); - } - if (from->swfcl_tcp) { - to->swfcl_tcp = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO); - if (to->swfcl_tcp == NULL) - goto failed; - memcpy(to->swfcl_tcp, from->swfcl_tcp, - sizeof(*from->swfcl_tcp)); - } - if (from->swfcl_udp) { - to->swfcl_udp = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO); - if (to->swfcl_udp == NULL) - goto failed; - memcpy(to->swfcl_udp, from->swfcl_udp, - sizeof(*from->swfcl_udp)); - } - if (from->swfcl_sctp) { - to->swfcl_sctp = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO); - if (to->swfcl_sctp == NULL) - goto failed; - memcpy(to->swfcl_sctp, from->swfcl_sctp, - sizeof(*from->swfcl_sctp)); - } - - return (0); - failed: - switch_swfcl_free(to); - return (ENOBUFS); -} - -void -switch_swfcl_free(struct switch_flow_classify *swfcl) -{ - if (swfcl->swfcl_tunnel) - pool_put(&swfcl_pool, swfcl->swfcl_tunnel); - if (swfcl->swfcl_ether) - pool_put(&swfcl_pool, swfcl->swfcl_ether); - if (swfcl->swfcl_vlan) - pool_put(&swfcl_pool, swfcl->swfcl_vlan); - if (swfcl->swfcl_ipv4) - pool_put(&swfcl_pool, swfcl->swfcl_ipv4); - if (swfcl->swfcl_ipv6) - pool_put(&swfcl_pool, swfcl->swfcl_ipv6); - if (swfcl->swfcl_arp) - pool_put(&swfcl_pool, swfcl->swfcl_arp); - if (swfcl->swfcl_nd6) - pool_put(&swfcl_pool, swfcl->swfcl_nd6); - if (swfcl->swfcl_icmpv4) - pool_put(&swfcl_pool, swfcl->swfcl_icmpv4); - if (swfcl->swfcl_icmpv6) - pool_put(&swfcl_pool, swfcl->swfcl_icmpv6); - if (swfcl->swfcl_tcp) - pool_put(&swfcl_pool, swfcl->swfcl_tcp); - if (swfcl->swfcl_udp) - pool_put(&swfcl_pool, swfcl->swfcl_udp); - if (swfcl->swfcl_sctp) - pool_put(&swfcl_pool, swfcl->swfcl_sctp); - - memset(swfcl, 0, sizeof(*swfcl)); -} - -struct mbuf * -switch_flow_classifier_udp(struct mbuf *m, int *offset, - struct switch_flow_classify *swfcl) -{ - struct udphdr *uh; - - swfcl->swfcl_udp = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO); - if (swfcl->swfcl_udp == NULL) { - m_freem(m); - return (NULL); - } - - if (m->m_len < (*offset + sizeof(*uh)) && - (m = m_pullup(m, *offset + sizeof(*uh))) == NULL) - return (NULL); - - uh = (struct udphdr *)((m)->m_data + *offset); - - swfcl->swfcl_udp->udp_src = uh->uh_sport; - swfcl->swfcl_udp->udp_dst = uh->uh_dport; - - return (m); -} - -struct mbuf * -switch_flow_classifier_tcp(struct mbuf *m, int *offset, - struct switch_flow_classify *swfcl) -{ - struct tcphdr *th; - - swfcl->swfcl_tcp = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO); - if (swfcl->swfcl_tcp == NULL) { - m_freem(m); - return (NULL); - } - - if (m->m_len < (*offset + sizeof(*th)) && - (m = m_pullup(m, *offset + sizeof(*th))) == NULL) - return (NULL); - - th = (struct tcphdr *)((m)->m_data + *offset); - - swfcl->swfcl_tcp->tcp_src = th->th_sport; - swfcl->swfcl_tcp->tcp_dst = th->th_dport; - swfcl->swfcl_tcp->tcp_flags = th->th_flags; - - return (m); -} - -struct mbuf * -switch_flow_classifier_icmpv4(struct mbuf *m, int *offset, - struct switch_flow_classify *swfcl) -{ - struct icmp *icmp; - - swfcl->swfcl_icmpv4 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO); - if (swfcl->swfcl_icmpv4 == NULL) { - m_freem(m); - return (NULL); - } - - if (m->m_len < (*offset + ICMP_MINLEN) && - (m = m_pullup(m, (*offset + ICMP_MINLEN))) == NULL) - return (NULL); - - icmp = (struct icmp *)((m)->m_data + *offset); - - swfcl->swfcl_icmpv4->icmpv4_type = icmp->icmp_type; - swfcl->swfcl_icmpv4->icmpv4_code = icmp->icmp_code; - - return (m); -} - -#ifdef INET6 -struct mbuf * -switch_flow_classifier_nd6(struct mbuf *m, int *offset, - struct switch_flow_classify *swfcl) -{ - struct icmp6_hdr *icmp6; - struct nd_neighbor_advert *nd_na; - struct nd_neighbor_solicit *nd_ns; - union nd_opts ndopts; - uint8_t *lladdr; - int lladdrlen; - int icmp6len = m->m_pkthdr.len - *offset; - - IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, *offset, sizeof(*icmp6)); - if (icmp6 == NULL) - goto failed; - - switch (icmp6->icmp6_type) { - case ND_NEIGHBOR_ADVERT: - if (icmp6len < sizeof(struct nd_neighbor_advert)) - goto failed; - break; - case ND_NEIGHBOR_SOLICIT: - if (icmp6len < sizeof(struct nd_neighbor_solicit)) - goto failed; - break; - } - - swfcl->swfcl_nd6 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO); - if (swfcl->swfcl_nd6 == NULL) - goto failed; - - switch (icmp6->icmp6_type) { - case ND_NEIGHBOR_ADVERT: - IP6_EXTHDR_GET(nd_na, struct nd_neighbor_advert *, m, - *offset, icmp6len); - - if (nd_na == NULL) - goto failed; - - swfcl->swfcl_nd6->nd6_target = nd_na->nd_na_target; - icmp6len -= sizeof(*nd_na); - nd6_option_init(nd_na + 1, icmp6len, &ndopts); - if (nd6_options(&ndopts) < 0) - goto failed; - - if (!ndopts.nd_opts_tgt_lladdr) - goto failed; - - lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1); - lladdrlen = (ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3) - 2; - - /* switch(4) only supports Ethernet interfaces */ - if (lladdrlen != ETHER_ADDR_LEN) - goto failed; - memcpy(swfcl->swfcl_nd6->nd6_lladdr, lladdr, ETHER_ADDR_LEN); - break; - case ND_NEIGHBOR_SOLICIT: - IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m, - *offset, icmp6len); - if (nd_ns == NULL) - goto failed; - swfcl->swfcl_nd6->nd6_target = nd_ns->nd_ns_target; - icmp6len -= sizeof(*nd_ns); - - nd6_option_init(nd_ns + 1, icmp6len, &ndopts); - if (nd6_options(&ndopts) < 0) - goto failed; - - if (!ndopts.nd_opts_src_lladdr) - goto failed; - lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); - lladdrlen = (ndopts.nd_opts_src_lladdr->nd_opt_len << 3) - 2; - - /* switch(4) only supports Ethernet interfaces */ - if (lladdrlen != ETHER_ADDR_LEN) - goto failed; - memcpy(swfcl->swfcl_nd6->nd6_lladdr, lladdr, ETHER_ADDR_LEN); - - break; - } - - return (m); - - failed: - m_freem(m); - return (NULL); -} - -struct mbuf * -switch_flow_classifier_icmpv6(struct mbuf *m, int *offset, - struct switch_flow_classify *swfcl) -{ - struct icmp6_hdr *icmp6; - - swfcl->swfcl_icmpv6 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO); - if (swfcl->swfcl_icmpv6 == NULL) { - m_freem(m); - return (NULL); - } - - IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, *offset, sizeof(*icmp6)); - if (icmp6 == NULL) - return (NULL); /* m was already freed */ - - swfcl->swfcl_icmpv6->icmpv6_type = icmp6->icmp6_type; - swfcl->swfcl_icmpv6->icmpv6_code = icmp6->icmp6_code; - - switch (icmp6->icmp6_type) { - case ND_NEIGHBOR_SOLICIT: - case ND_NEIGHBOR_ADVERT: - return switch_flow_classifier_nd6(m, offset, swfcl); - } - - return (m); -} -#endif /* INET6 */ - -struct mbuf * -switch_flow_classifier_ipv4(struct mbuf *m, int *offset, - struct switch_flow_classify *swfcl) -{ - struct ip *ip; - - swfcl->swfcl_ipv4 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO); - if (swfcl->swfcl_ipv4 == NULL) { - m_freem(m); - return (NULL); - } - - if (m->m_len < (*offset + sizeof(*ip)) && - (m = m_pullup(m, *offset + sizeof(*ip))) == NULL) - return (NULL); - - ip = (struct ip *)((m)->m_data + *offset); - - swfcl->swfcl_ipv4->ipv4_tos = ip->ip_tos; - swfcl->swfcl_ipv4->ipv4_ttl = ip->ip_ttl; - swfcl->swfcl_ipv4->ipv4_proto = ip->ip_p; - - memcpy(&swfcl->swfcl_ipv4->ipv4_src, &ip->ip_src.s_addr, - sizeof(uint32_t)); - memcpy(&swfcl->swfcl_ipv4->ipv4_dst, &ip->ip_dst.s_addr, - sizeof(uint32_t)); - - *offset += (ip->ip_hl << 2); - - switch (ip->ip_p) { - case IPPROTO_UDP: - return switch_flow_classifier_udp(m, offset, swfcl); - case IPPROTO_TCP: - return switch_flow_classifier_tcp(m, offset, swfcl); - case IPPROTO_ICMP: - return switch_flow_classifier_icmpv4(m, offset, swfcl); - } - - return (m); -} - -#ifdef INET6 -struct mbuf * -switch_flow_classifier_ipv6(struct mbuf *m, int *offset, - struct switch_flow_classify *swfcl) -{ - struct ip6_hdr *ip6; - - swfcl->swfcl_ipv6 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO); - if (swfcl->swfcl_ipv6 == NULL) { - m_freem(m); - return (NULL); - } - - if (m->m_len < (*offset + sizeof(*ip6)) && - (m = m_pullup(m, *offset + sizeof(*ip6))) == NULL) - return (NULL); - - ip6 = (struct ip6_hdr *)((m)->m_data + *offset); - - swfcl->swfcl_ipv6->ipv6_src = ip6->ip6_src; - swfcl->swfcl_ipv6->ipv6_dst = ip6->ip6_dst; - swfcl->swfcl_ipv6->ipv6_flow_label = - (ip6->ip6_flow & IPV6_FLOWLABEL_MASK); - swfcl->swfcl_ipv6->ipv6_tclass = (ntohl(ip6->ip6_flow) >> 20); - swfcl->swfcl_ipv6->ipv6_hlimit = ip6->ip6_hlim; - swfcl->swfcl_ipv6->ipv6_nxt = ip6->ip6_nxt; - - *offset += sizeof(*ip6); - - switch (ip6->ip6_nxt) { - case IPPROTO_UDP: - return switch_flow_classifier_udp(m, offset, swfcl); - case IPPROTO_TCP: - return switch_flow_classifier_tcp(m, offset, swfcl); - case IPPROTO_ICMPV6: - return switch_flow_classifier_icmpv6(m, offset, swfcl); - } - - return (m); -} -#endif /* INET6 */ - -struct mbuf * -switch_flow_classifier_arp(struct mbuf *m, int *offset, - struct switch_flow_classify *swfcl) -{ - struct ether_arp *ea; - - swfcl->swfcl_arp = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO); - if (swfcl->swfcl_arp == NULL) { - m_freem(m); - return (NULL); - } - - if (m->m_len < (*offset + sizeof(*ea)) && - (m = m_pullup(m, *offset + sizeof(*ea))) == NULL) - return (NULL); - - ea = (struct ether_arp *)((m)->m_data + *offset); - - swfcl->swfcl_arp->_arp_op = ea->arp_op; - - memcpy(swfcl->swfcl_arp->arp_sha, &ea->arp_sha, ETHER_ADDR_LEN); - memcpy(swfcl->swfcl_arp->arp_tha, &ea->arp_tha, ETHER_ADDR_LEN); - memcpy(&swfcl->swfcl_arp->arp_sip, &ea->arp_spa, sizeof(uint32_t)); - memcpy(&swfcl->swfcl_arp->arp_tip, &ea->arp_tpa, sizeof(uint32_t)); - - return (m); -} - -struct mbuf * -switch_flow_classifier_ether(struct mbuf *m, int *offset, - struct switch_flow_classify *swfcl) -{ - struct ether_header *eh; - struct ether_vlan_header *evl; - uint16_t ether_type; - - swfcl->swfcl_ether = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO); - if (swfcl->swfcl_ether == NULL) { - m_freem(m); - return (NULL); - } - - if (m->m_len < sizeof(*eh) && (m = m_pullup(m, sizeof(*eh))) == NULL) - return (NULL); - eh = mtod(m, struct ether_header *); - - memcpy(swfcl->swfcl_ether->eth_src, eh->ether_shost, ETHER_ADDR_LEN); - memcpy(swfcl->swfcl_ether->eth_dst, eh->ether_dhost, ETHER_ADDR_LEN); - - if ((m->m_flags & M_VLANTAG) || - (ntohs(eh->ether_type) == ETHERTYPE_VLAN) || - (ntohs(eh->ether_type) == ETHERTYPE_QINQ)) { - swfcl->swfcl_vlan = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO); - if (swfcl->swfcl_vlan == NULL) { - m_freem(m); - return (NULL); - } - } - - if (m->m_flags & M_VLANTAG) { - /* - * Hardware VLAN tagging is only supported for 801.1Q VLAN, - * but not for 802.1ad QinQ. - */ - swfcl->swfcl_vlan->vlan_tpid = htons(ETHERTYPE_VLAN); - swfcl->swfcl_vlan->vlan_vid = - htons(EVL_VLANOFTAG(m->m_pkthdr.ether_vtag)); - swfcl->swfcl_vlan->vlan_pcp = - EVL_PRIOFTAG(m->m_pkthdr.ether_vtag); - ether_type = eh->ether_type; - *offset += sizeof(*eh); - } else if (ntohs(eh->ether_type) == ETHERTYPE_VLAN) { - if (m->m_len < sizeof(*evl) && - (m = m_pullup(m, sizeof(*evl))) == NULL) - return (NULL); - evl = mtod(m, struct ether_vlan_header *); - - /* - * Software VLAN tagging is currently only supported for - * 801.1Q VLAN, but not for 802.1ad QinQ. - */ - swfcl->swfcl_vlan->vlan_tpid = htons(ETHERTYPE_VLAN); - swfcl->swfcl_vlan->vlan_vid = - (evl->evl_tag & htons(EVL_VLID_MASK)); - swfcl->swfcl_vlan->vlan_pcp = - EVL_PRIOFTAG(ntohs(evl->evl_tag)); - ether_type = evl->evl_proto; - *offset += sizeof(*evl); - } else { - ether_type = eh->ether_type; - *offset += sizeof(*eh); - } - - swfcl->swfcl_ether->eth_type = ether_type; - - ether_type = ntohs(ether_type); - switch (ether_type) { - case ETHERTYPE_ARP: - return switch_flow_classifier_arp(m, offset, swfcl); - case ETHERTYPE_IP: - return switch_flow_classifier_ipv4(m, offset, swfcl); -#ifdef INET6 - case ETHERTYPE_IPV6: - return switch_flow_classifier_ipv6(m, offset, swfcl); -#endif /* INET6 */ - case ETHERTYPE_MPLS: - /* unsupported yet */ - break; - } - - return (m); -} - -struct mbuf * -switch_flow_classifier_tunnel(struct mbuf *m, int *offset, - struct switch_flow_classify *swfcl) -{ - struct bridge_tunneltag *brtag; - - if ((brtag = bridge_tunnel(m)) == NULL) - goto out; - - if ((brtag->brtag_peer.sa.sa_family != AF_INET) && - (brtag->brtag_peer.sa.sa_family != AF_INET6)) - goto out; - - swfcl->swfcl_tunnel = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO); - if (swfcl->swfcl_tunnel == NULL) { - m_freem(m); - return (NULL); - } - - swfcl->swfcl_tunnel->tun_af = brtag->brtag_peer.sa.sa_family; - swfcl->swfcl_tunnel->tun_key = htobe64(brtag->brtag_id); - if (swfcl->swfcl_tunnel->tun_af == AF_INET) { - swfcl->swfcl_tunnel->tun_ipv4_src = - brtag->brtag_local.sin.sin_addr; - swfcl->swfcl_tunnel->tun_ipv4_dst = - brtag->brtag_peer.sin.sin_addr; - } else { - swfcl->swfcl_tunnel->tun_ipv6_src = - brtag->brtag_local.sin6.sin6_addr; - swfcl->swfcl_tunnel->tun_ipv6_dst = - brtag->brtag_peer.sin6.sin6_addr; - } - bridge_tunneluntag(m); - out: - return switch_flow_classifier_ether(m, offset, swfcl); -} - -struct mbuf * -switch_flow_classifier(struct mbuf *m, uint32_t in_port, - struct switch_flow_classify *swfcl) -{ - int offset = 0; - - memset(swfcl, 0, sizeof(*swfcl)); - swfcl->swfcl_in_port = in_port; - - return switch_flow_classifier_tunnel(m, &offset, swfcl); -} - -void -switch_flow_classifier_dump(struct switch_softc *sc, - struct switch_flow_classify *swfcl) -{ - char saddr[INET6_ADDRSTRLEN], daddr[INET6_ADDRSTRLEN]; - - log(LOG_DEBUG, "%s: ", sc->sc_if.if_xname); - addlog("in_port(%u),", swfcl->swfcl_in_port); - - if (swfcl->swfcl_tunnel) { - if (swfcl->swfcl_tunnel->tun_af == AF_INET) { - inet_ntop(AF_INET, - (void *)&swfcl->swfcl_tunnel->tun_ipv4_src, - saddr, sizeof(saddr)); - inet_ntop(AF_INET, - (void *)&swfcl->swfcl_tunnel->tun_ipv4_dst, - daddr, sizeof(daddr)); - addlog("tun_ipv4_src(%s),tun_ipv4_dst(%s)," - "tun_id(%llu),", saddr, daddr, - be64toh(swfcl->swfcl_tunnel->tun_key)); - } else if (swfcl->swfcl_tunnel->tun_af == AF_INET6) { - inet_ntop(AF_INET6, - (void *)&swfcl->swfcl_tunnel->tun_ipv6_src, - saddr, sizeof(saddr)); - inet_ntop(AF_INET6, - (void *)&swfcl->swfcl_tunnel->tun_ipv6_dst, - daddr, sizeof(daddr)); - addlog("tun_ipv6_src(%s) tun_ipv6_dst(%s)," - "tun_id(%llu),", saddr, daddr, - be64toh(swfcl->swfcl_tunnel->tun_key)); - } - } - - if (swfcl->swfcl_vlan) { - addlog("vlan_tpid(0x%0x4x),vlan_pcp(%u),vlan_vid(%u),", - ntohs(swfcl->swfcl_vlan->vlan_tpid), - swfcl->swfcl_vlan->vlan_pcp, - ntohs(swfcl->swfcl_vlan->vlan_vid)); - } - - if (swfcl->swfcl_ether) { - addlog("eth_dst(%s),eth_src(%s),eth_type(0x%04x)", - ether_sprintf(swfcl->swfcl_ether->eth_dst), - ether_sprintf(swfcl->swfcl_ether->eth_src), - ntohs(swfcl->swfcl_ether->eth_type)); - } - - if (swfcl->swfcl_arp) { - inet_ntop(AF_INET, (void *)&swfcl->swfcl_arp->arp_sip, - saddr, sizeof(saddr)); - inet_ntop(AF_INET, (void *)&swfcl->swfcl_arp->arp_tip, - daddr, sizeof(daddr)); - addlog("arp_op(%x),arp_tha(%s),arp_sha(%s),arp_sip(%s)," - "arp_tip(%s),", swfcl->swfcl_arp->_arp_op, - ether_sprintf(swfcl->swfcl_arp->arp_tha), - ether_sprintf(swfcl->swfcl_arp->arp_sha), saddr, daddr); - } - - if (swfcl->swfcl_ipv4) { - inet_ntop(AF_INET, (void *)&swfcl->swfcl_ipv4->ipv4_src, - saddr, sizeof(saddr)); - inet_ntop(AF_INET, (void *)&swfcl->swfcl_ipv4->ipv4_dst, - daddr, sizeof(daddr)); - addlog("ip_proto(%u),ip_tos(%u),ip_ttl(%u),ip_src(%s)," - "ip_dst(%s),", swfcl->swfcl_ipv4->ipv4_proto, - swfcl->swfcl_ipv4->ipv4_tos, swfcl->swfcl_ipv4->ipv4_ttl, - saddr, daddr); - } - - if (swfcl->swfcl_ipv6) { - inet_ntop(AF_INET6, (void *)&swfcl->swfcl_ipv6->ipv6_src, - saddr, sizeof(saddr)); - inet_ntop(AF_INET6, (void *)&swfcl->swfcl_ipv6->ipv6_dst, - daddr, sizeof(daddr)); - addlog("ip6_nxt(%u),ip6_flow_label(%u),ip6_tclass(%d)," - "ip6_hlimit(%u),ip6_src(%s),ip6_dst(%s),", - swfcl->swfcl_ipv6->ipv6_nxt, - ntohl(swfcl->swfcl_ipv6->ipv6_flow_label), - swfcl->swfcl_ipv6->ipv6_tclass, - swfcl->swfcl_ipv6->ipv6_hlimit, saddr, daddr); - } - - if (swfcl->swfcl_icmpv4) { - addlog("icmp_type(%u),icmp_code(%u),", - swfcl->swfcl_icmpv4->icmpv4_type, - swfcl->swfcl_icmpv4->icmpv4_code); - } - - if (swfcl->swfcl_icmpv6) { - addlog("icmp6_type(%u),icmp6_code(%u),", - swfcl->swfcl_icmpv6->icmpv6_type, - swfcl->swfcl_icmpv6->icmpv6_code); - } - - if (swfcl->swfcl_nd6) { - inet_ntop(AF_INET6, (void *)&swfcl->swfcl_nd6->nd6_target, - saddr, sizeof(saddr)); - addlog("nd_target(%s),nd_lladdr(%s),", saddr, - ether_sprintf(swfcl->swfcl_nd6->nd6_lladdr)); - } - - if (swfcl->swfcl_tcp) { - addlog("tcp_src(%u),tcp_dst(%u),tcp_flags(%x),", - ntohs(swfcl->swfcl_tcp->tcp_src), - ntohs(swfcl->swfcl_tcp->tcp_dst), - swfcl->swfcl_tcp->tcp_flags); - } - - if (swfcl->swfcl_udp) { - addlog("udp_src(%u),udp_dst(%u),", - ntohs(swfcl->swfcl_udp->udp_src), - ntohs(swfcl->swfcl_udp->udp_dst)); - } - - addlog("\n"); -} - -int -switch_mtap(caddr_t arg, struct mbuf *m, int dir, uint64_t datapath_id) -{ -#if NBPFILTER > 0 - struct dlt_openflow_hdr of; - - of.of_datapath_id = htobe64(datapath_id); - of.of_direction = htonl(dir == BPF_DIRECTION_IN ? - DLT_OPENFLOW_TO_SWITCH : DLT_OPENFLOW_TO_CONTROLLER); - - return (bpf_mtap_hdr(arg, (caddr_t)&of, sizeof(of), m, dir)); -#else - return (0); -#endif -} - -int -ofp_split_mbuf(struct mbuf *m, struct mbuf **mtail) -{ - uint16_t ohlen; - - *mtail = NULL; - - again: - /* We need more data. */ - KASSERT(m->m_flags & M_PKTHDR); - if (m->m_pkthdr.len < sizeof(struct ofp_header)) - return (-1); - - m_copydata(m, offsetof(struct ofp_header, oh_length), sizeof(ohlen), - &ohlen); - ohlen = ntohs(ohlen); - - /* We got an invalid packet header, skip it. */ - if (ohlen < sizeof(struct ofp_header)) { - m_adj(m, sizeof(struct ofp_header)); - goto again; - } - - /* Nothing to split. */ - if (m->m_pkthdr.len == ohlen) - return (0); - else if (m->m_pkthdr.len < ohlen) - return (-1); - - *mtail = m_split(m, ohlen, M_NOWAIT); - /* No memory, try again later. */ - if (*mtail == NULL) - return (-1); - - return (0); -} - -void -switch_take(void *unused) -{ - return; -} - -void -switch_rele(void *unused) -{ - return; -} diff --git a/sys/net/if_switch.h b/sys/net/if_switch.h deleted file mode 100644 index f8bd6df55f9..00000000000 --- a/sys/net/if_switch.h +++ /dev/null @@ -1,240 +0,0 @@ -/* $OpenBSD: if_switch.h,v 1.12 2019/11/06 03:51:26 dlg Exp $ */ - -/* - * Copyright (c) 2016 Kazuya GODA - * Copyright (c) 2016 Reyk Floeter - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _NET_IF_SWITCH_H_ -#define _NET_IF_SWITCH_H_ - -/* capabilities for switch(4) */ -#define SWITCH_CAP_STP 0x0001 -#define SWITCH_CAP_LEARNING 0x0002 -#define SWITCH_CAP_OFP 0x0004 - -#ifdef _KERNEL - -struct switch_field_tunnel { - uint32_t tun_af; - struct in_addr tun_ipv4_src; - struct in_addr tun_ipv4_dst; - struct in6_addr tun_ipv6_src; - struct in6_addr tun_ipv6_dst; - uint64_t tun_key; -}; - -struct switch_field_ether { - uint8_t eth_src[ETHER_ADDR_LEN]; - uint8_t __pad_eth_src[2]; - uint8_t eth_dst[ETHER_ADDR_LEN]; - uint8_t __pad_eth_dst[2]; - uint16_t eth_type; - uint8_t __pad_eth_type[2]; -}; - -struct switch_field_vlan { - uint16_t vlan_tpid; - uint16_t vlan_vid; - uint16_t vlan_pcp; - uint8_t __pad_vlan_pcp[2]; -}; - -struct switch_field_ipv4 { - uint32_t ipv4_src; - uint32_t ipv4_dst; - uint8_t ipv4_proto; - uint8_t ipv4_tos; - uint8_t ipv4_ttl; - uint8_t ipv4_frag; -}; - -struct switch_field_ipv6 { - struct in6_addr ipv6_src; - struct in6_addr ipv6_dst; - uint32_t ipv6_flow_label; - uint8_t ipv6_nxt; - uint8_t ipv6_tclass; - uint8_t ipv6_hlimit; - uint8_t ipv6_frag; -}; - -struct switch_field_arp { - uint16_t _arp_op; - uint8_t __pad_arp_op[2]; - uint8_t arp_sha[ETHER_ADDR_LEN]; - uint8_t __pad_arp_sha[2]; - uint8_t arp_tha[ETHER_ADDR_LEN]; - uint8_t __pad_arp_tha[2]; - uint32_t arp_sip; - uint32_t arp_tip; -}; - -struct switch_field_nd6 { - struct in6_addr nd6_target; - uint8_t nd6_lladdr[ETHER_ADDR_LEN]; - uint8_t __pad_nd6_lladdr[2]; -}; - -struct switch_field_icmpv4 { - uint8_t icmpv4_type; - uint8_t icmpv4_code; - uint8_t __pad[2]; -}; - -struct switch_field_icmpv6 { - uint8_t icmpv6_type; - uint8_t icmpv6_code; - uint8_t __pad[2]; -}; - -struct switch_field_tcp { - uint16_t tcp_src; - uint16_t tcp_dst; - uint8_t tcp_flags; - uint8_t __pad[3]; -}; - -struct switch_field_udp { - uint16_t udp_src; - uint16_t udp_dst; -}; - -struct switch_field_sctp { - uint16_t sctp_src; - uint16_t sctp_dst; -}; - -union switch_field { - struct switch_field_tunnel swfcl_tunnel; - struct switch_field_ether swfcl_ether; - struct switch_field_vlan swfcl_vlan; - struct switch_field_ipv4 swfcl_ipv4; - struct switch_field_ipv6 swfcl_ipv6; - struct switch_field_arp swfcl_arp; - struct switch_field_nd6 swfcl_nd6; - struct switch_field_icmpv4 swfcl_icmpv4; - struct switch_field_icmpv6 swfcl_icmpv6; - struct switch_field_tcp swfcl_tcp; - struct switch_field_udp swfcl_udp; - struct switch_field_sctp swfcl_sctp; -}; - -struct switch_flow_classify { - uint64_t swfcl_flow_hash; - - /* - * Pipeline field on OpenFlow switch specific - */ - uint64_t swfcl_metadata; - uint64_t swfcl_cookie; - uint8_t swfcl_table_id; - - /* - * Classify field without protocol headers - */ - uint32_t swfcl_in_port; - - /* - * Classify field from protocol headers - */ - struct switch_field_tunnel *swfcl_tunnel; - struct switch_field_ether *swfcl_ether; - struct switch_field_vlan *swfcl_vlan; - struct switch_field_ipv4 *swfcl_ipv4; - struct switch_field_ipv6 *swfcl_ipv6; - struct switch_field_arp *swfcl_arp; - struct switch_field_nd6 *swfcl_nd6; - struct switch_field_icmpv4 *swfcl_icmpv4; - struct switch_field_icmpv6 *swfcl_icmpv6; - struct switch_field_tcp *swfcl_tcp; - struct switch_field_udp *swfcl_udp; - struct switch_field_sctp *swfcl_sctp; -}; - -struct switch_softc; - -struct switch_port { - TAILQ_ENTRY(switch_port) swpo_list_next; - TAILQ_ENTRY(switch_port) swpo_fwdp_next; - uint32_t swpo_port_no; - uint32_t swpo_ifindex; - struct timespec swpo_appended; - struct switch_softc *swpo_switch; - uint32_t swpo_flags; - uint32_t swpo_protected; - struct task swpo_dtask; - void (*swop_bk_start)(struct ifnet *); -}; - -TAILQ_HEAD(switch_fwdp_queue, switch_port); - -struct switch_dev { - struct mbuf *swdev_lastm; - struct mbuf *swdev_inputm; - struct mbuf_queue swdev_outq; - struct selinfo swdev_rsel; - struct selinfo swdev_wsel; - int swdev_waiting; - void (*swdev_init)(struct switch_softc *); - int (*swdev_input)(struct switch_softc *, - struct mbuf *); - int (*swdev_output)(struct switch_softc *, - struct mbuf *); -}; - -struct switch_softc { - struct ifnet sc_if; - int sc_unit; - uint32_t sc_capabilities; - struct switch_dev *sc_swdev; /* char device */ - struct bstp_state *sc_stp; /* STP state */ - struct swofp_ofs *sc_ofs; /* OpenFlow */ - caddr_t sc_ofbpf; /* DLT_OPENFLOW */ - TAILQ_HEAD(,switch_port) sc_swpo_list; /* port */ - LIST_ENTRY(switch_softc) sc_switch_next; /* switch link */ - void (*switch_process_forward)( - struct switch_softc *, struct switch_flow_classify *, - struct mbuf *); -}; - -/* if_switch.c */ -struct switch_softc - *switch_lookup(int); -void switch_port_egress(struct switch_softc *, struct switch_fwdp_queue *, - struct mbuf *); -int switch_swfcl_dup(struct switch_flow_classify *, - struct switch_flow_classify *); -void switch_swfcl_free(struct switch_flow_classify *); -struct mbuf - *switch_flow_classifier(struct mbuf *, uint32_t, - struct switch_flow_classify *); -int switch_mtap(caddr_t, struct mbuf *, int, uint64_t); -int ofp_split_mbuf(struct mbuf *, struct mbuf **); - -/* switchctl.c */ -void switch_dev_destroy(struct switch_softc *); - -/* in switchofp.c */ -void swofp_attach(void); -int swofp_create(struct switch_softc *); -int swofp_init(struct switch_softc *); -void swofp_destroy(struct switch_softc *); -int swofp_ioctl(struct ifnet *, unsigned long, caddr_t); -uint32_t - swofp_assign_portno(struct switch_softc *, uint32_t); - -#endif /* _KERNEL */ -#endif /* _NET_IF_SWITCH_H_ */ diff --git a/sys/net/switchctl.c b/sys/net/switchctl.c deleted file mode 100644 index 94eacec20b5..00000000000 --- a/sys/net/switchctl.c +++ /dev/null @@ -1,475 +0,0 @@ -/* $OpenBSD: switchctl.c,v 1.23 2020/12/25 12:59:53 visa Exp $ */ - -/* - * Copyright (c) 2016 Kazuya GODA - * Copyright (c) 2015, 2016 YASUOKA Masahiko - * Copyright (c) 2015, 2016 Reyk Floeter - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include - -extern struct rwlock switch_ifs_lk; - -/* - * device part of switch(4) - */ -#include -#include -#include - -struct switch_softc *switch_dev2sc(dev_t); -int switchopen(dev_t, int, int, struct proc *); -int switchread(dev_t, struct uio *, int); -int switchwrite(dev_t, struct uio *, int); -int switchioctl(dev_t, u_long, caddr_t, int, struct proc *); -int switchclose(dev_t, int, int, struct proc *); -int switchpoll(dev_t, int, struct proc *); -int switchkqfilter(dev_t, struct knote *); -void filt_switch_rdetach(struct knote *); -int filt_switch_read(struct knote *, long); -void filt_switch_wdetach(struct knote *); -int filt_switch_write(struct knote *, long); -int switch_dev_output(struct switch_softc *, struct mbuf *); -void switch_dev_wakeup(struct switch_softc *); - -const struct filterops switch_rd_filtops = { - .f_flags = FILTEROP_ISFD, - .f_attach = NULL, - .f_detach = filt_switch_rdetach, - .f_event = filt_switch_read, -}; - -const struct filterops switch_wr_filtops = { - .f_flags = FILTEROP_ISFD, - .f_attach = NULL, - .f_detach = filt_switch_wdetach, - .f_event = filt_switch_write, -}; - -struct switch_softc * -switch_dev2sc(dev_t dev) -{ - struct switch_softc *sc; - - rw_enter_read(&switch_ifs_lk); - sc = switch_lookup(minor(dev)); - rw_exit_read(&switch_ifs_lk); - - return (sc); -} - -int -switchopen(dev_t dev, int flags, int mode, struct proc *p) -{ - struct switch_softc *sc; - char name[IFNAMSIZ]; - int rv, s, error = 0; - unsigned int rdomain = rtable_l2(p->p_p->ps_rtableid); - - if ((sc = switch_dev2sc(dev)) == NULL) { - snprintf(name, sizeof(name), "switch%d", minor(dev)); - rv = if_clone_create(name, rdomain); - if (rv != 0) - return (rv); - if ((sc = switch_dev2sc(dev)) == NULL) - return (ENXIO); - } - - rw_enter_write(&switch_ifs_lk); - if (sc->sc_swdev != NULL) { - error = EBUSY; - goto failed; - } - - if ((sc->sc_swdev = malloc(sizeof(struct switch_dev), M_DEVBUF, - M_DONTWAIT|M_ZERO)) == NULL ) { - error = ENOBUFS; - goto failed; - } - - s = splnet(); - mq_init(&sc->sc_swdev->swdev_outq, 128, IPL_NET); - - sc->sc_swdev->swdev_output = switch_dev_output; - if (sc->sc_capabilities & SWITCH_CAP_OFP) - swofp_init(sc); - - splx(s); - - failed: - rw_exit_write(&switch_ifs_lk); - return (error); - -} - -int -switchread(dev_t dev, struct uio *uio, int ioflag) -{ - struct switch_softc *sc; - struct mbuf *m; - u_int len; - int s, error = 0; - - sc = switch_dev2sc(dev); - if (sc == NULL) - return (ENXIO); - - if (sc->sc_swdev->swdev_lastm != NULL) { - m = sc->sc_swdev->swdev_lastm; - sc->sc_swdev->swdev_lastm = NULL; - goto skip_dequeue; - } - - dequeue_next: - s = splnet(); - while ((m = mq_dequeue(&sc->sc_swdev->swdev_outq)) == NULL) { - if (ISSET(ioflag, IO_NDELAY)) { - error = EWOULDBLOCK; - goto failed; - } - sc->sc_swdev->swdev_waiting = 1; - error = tsleep_nsec(sc, (PZERO + 1)|PCATCH, "switchread", - INFSLP); - if (error != 0) - goto failed; - /* sc might be deleted while sleeping */ - sc = switch_dev2sc(dev); - if (sc == NULL) { - error = ENXIO; - goto failed; - } - } - splx(s); - - skip_dequeue: - while (uio->uio_resid > 0) { - len = ulmin(uio->uio_resid, m->m_len); - if ((error = uiomove(mtod(m, caddr_t), len, uio)) != 0) { - /* Save it so user can recover from EFAULT. */ - sc->sc_swdev->swdev_lastm = m; - return (error); - } - - /* Handle partial reads. */ - if (uio->uio_resid == 0) { - if (len < m->m_len) - m_adj(m, len); - else - m = m_free(m); - sc->sc_swdev->swdev_lastm = m; - break; - } - - /* - * After consuming data from this mbuf test if we - * have to dequeue a new chain. - */ - m = m_free(m); - if (m == NULL) - goto dequeue_next; - } - - return (0); -failed: - splx(s); - return (error); -} - -int -switchwrite(dev_t dev, struct uio *uio, int ioflag) -{ - struct switch_softc *sc = NULL; - struct mbuf *m, *n, *mhead, *mtail = NULL; - int s, error, trailing; - size_t len; - - if (uio->uio_resid == 0) - return (0); - - len = uio->uio_resid; - - sc = switch_dev2sc(dev); - if (sc == NULL) - return (ENXIO); - - if (sc->sc_swdev->swdev_inputm == NULL) { - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) - return (ENOBUFS); - if (len >= MHLEN) { - MCLGETL(m, M_DONTWAIT, MIN(MAXMCLBYTES, len)); - if ((m->m_flags & M_EXT) == 0) { - m_free(m); - return (ENOBUFS); - } - } - mhead = m; - - /* m_trailingspace() uses this to calculate space. */ - m->m_len = 0; - } else { - /* Recover the mbuf from the last write and get its tail. */ - mhead = sc->sc_swdev->swdev_inputm; - for (m = mhead; m->m_next != NULL; m = m->m_next) - /* NOTHING */; - - sc->sc_swdev->swdev_inputm = NULL; - } - KASSERT(mhead->m_flags & M_PKTHDR); - - while (len) { - trailing = ulmin(m_trailingspace(m), len); - if ((error = uiomove(mtod(m, caddr_t) + m->m_len, trailing, - uio)) != 0) - goto save_return; - - len -= trailing; - mhead->m_pkthdr.len += trailing; - m->m_len += trailing; - if (len == 0) - break; - - MGET(n, M_DONTWAIT, MT_DATA); - if (n == NULL) { - error = ENOBUFS; - goto save_return; - } - if (len >= MLEN) { - MCLGETL(n, M_DONTWAIT, MIN(MAXMCLBYTES, len)); - if ((n->m_flags & M_EXT) == 0) { - m_free(n); - error = ENOBUFS; - goto save_return; - } - } - n->m_len = 0; - - m->m_next = n; - m = n; - } - - /* Loop until there is no more complete OFP packets. */ - while (ofp_split_mbuf(mhead, &mtail) == 0) { - s = splnet(); - sc->sc_swdev->swdev_input(sc, mhead); - splx(s); - - /* We wrote everything, just quit. */ - if (mtail == NULL) - return (0); - - mhead = mtail; - } - - /* Save the head, because ofp_split_mbuf failed. */ - sc->sc_swdev->swdev_inputm = mhead; - - return (0); - - save_return: - /* Save it so user can recover from errors later. */ - sc->sc_swdev->swdev_inputm = mhead; - return (error); -} - -int -switchioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) -{ - int error; - - switch (cmd) { - case FIONBIO: - case FIOASYNC: - case FIONREAD: - return (0); - default: - error = ENOTTY; - break; - } - - return (error); -} - -int -switchclose(dev_t dev, int flags, int mode, struct proc *p) -{ - struct switch_softc *sc; - - rw_enter_write(&switch_ifs_lk); - sc = switch_lookup(minor(dev)); - if (sc != NULL && sc->sc_swdev != NULL) { - m_freem(sc->sc_swdev->swdev_lastm); - m_freem(sc->sc_swdev->swdev_inputm); - mq_purge(&sc->sc_swdev->swdev_outq); - free(sc->sc_swdev, M_DEVBUF, sizeof(struct switch_dev)); - sc->sc_swdev = NULL; - } - rw_exit_write(&switch_ifs_lk); - - return (0); -} - -void -switch_dev_destroy(struct switch_softc *sc) -{ - int s; - - if (sc->sc_swdev == NULL) - return; - rw_enter_write(&switch_ifs_lk); - if (sc->sc_swdev != NULL) { - switch_dev_wakeup(sc); - - s = splhigh(); - klist_invalidate(&sc->sc_swdev->swdev_rsel.si_note); - klist_invalidate(&sc->sc_swdev->swdev_wsel.si_note); - splx(s); - - m_freem(sc->sc_swdev->swdev_lastm); - m_freem(sc->sc_swdev->swdev_inputm); - mq_purge(&sc->sc_swdev->swdev_outq); - free(sc->sc_swdev, M_DEVBUF, sizeof(struct switch_dev)); - sc->sc_swdev = NULL; - } - rw_exit_write(&switch_ifs_lk); -} - -int -switchpoll(dev_t dev, int events, struct proc *p) -{ - int revents = 0; - struct switch_softc *sc = switch_dev2sc(dev); - - if (sc == NULL) - return (POLLERR); - - if (events & (POLLIN | POLLRDNORM)) { - if (!mq_empty(&sc->sc_swdev->swdev_outq) || - sc->sc_swdev->swdev_lastm != NULL) - revents |= events & (POLLIN | POLLRDNORM); - } - if (events & (POLLOUT | POLLWRNORM)) - revents |= events & (POLLOUT | POLLWRNORM); - if (revents == 0) { - if (events & (POLLIN | POLLRDNORM)) - selrecord(p, &sc->sc_swdev->swdev_rsel); - } - - return (revents); -} - -int -switchkqfilter(dev_t dev, struct knote *kn) -{ - struct switch_softc *sc = switch_dev2sc(dev); - struct klist *klist; - - if (sc == NULL) - return (ENXIO); - - switch (kn->kn_filter) { - case EVFILT_READ: - klist = &sc->sc_swdev->swdev_rsel.si_note; - kn->kn_fop = &switch_rd_filtops; - break; - case EVFILT_WRITE: - klist = &sc->sc_swdev->swdev_wsel.si_note; - kn->kn_fop = &switch_wr_filtops; - break; - default: - return (EINVAL); - } - - kn->kn_hook = (caddr_t)sc; - - klist_insert_locked(klist, kn); - - return (0); -} - -void -filt_switch_rdetach(struct knote *kn) -{ - struct switch_softc *sc = (struct switch_softc *)kn->kn_hook; - struct klist *klist = &sc->sc_swdev->swdev_rsel.si_note; - - klist_remove_locked(klist, kn); -} - -int -filt_switch_read(struct knote *kn, long hint) -{ - struct switch_softc *sc = (struct switch_softc *)kn->kn_hook; - - if (!mq_empty(&sc->sc_swdev->swdev_outq) || - sc->sc_swdev->swdev_lastm != NULL) { - kn->kn_data = mq_len(&sc->sc_swdev->swdev_outq) + - (sc->sc_swdev->swdev_lastm != NULL); - return (1); - } - - return (0); -} - -void -filt_switch_wdetach(struct knote *kn) -{ - struct switch_softc *sc = (struct switch_softc *)kn->kn_hook; - struct klist *klist = &sc->sc_swdev->swdev_wsel.si_note; - - klist_remove_locked(klist, kn); -} - -int -filt_switch_write(struct knote *kn, long hint) -{ - /* Always writable */ - return (1); -} - -int -switch_dev_output(struct switch_softc *sc, struct mbuf *m) -{ - if (mq_enqueue(&sc->sc_swdev->swdev_outq, m) != 0) - return (-1); - switch_dev_wakeup(sc); - - return (0); -} - -void -switch_dev_wakeup(struct switch_softc *sc) -{ - if (sc->sc_swdev->swdev_waiting) { - sc->sc_swdev->swdev_waiting = 0; - wakeup((caddr_t)sc); - } - selwakeup(&sc->sc_swdev->swdev_rsel); -} diff --git a/sys/net/switchofp.c b/sys/net/switchofp.c deleted file mode 100644 index 9077d5d6d44..00000000000 --- a/sys/net/switchofp.c +++ /dev/null @@ -1,6671 +0,0 @@ -/* $OpenBSD: switchofp.c,v 1.80 2021/03/10 10:21:48 jsg Exp $ */ - -/* - * Copyright (c) 2016 Kazuya GODA - * Copyright (c) 2015, 2016 YASUOKA Masahiko - * Copyright (c) 2015, 2016 Reyk Floeter - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "bpfilter.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if NBPFILTER > 0 -#include -#endif - -/* - * Per-frame debugging can be done at any time using the BPF - * hook of DLT_OPENFLOW (eg. tcpdump -y openflow -i switch0) - */ -#ifdef DEBUG -#define DPRINTF(__sc, ...) \ -do { \ - struct switch_softc *_sc = __sc; \ - log(LOG_DEBUG, "%s: ", _sc->sc_if.if_xname); \ - addlog(__VA_ARGS__); \ -} while(/*CONSTCOND*/0) -#else -#define DPRINTF(__sc, ...) do {} while(0) -#endif - -struct swofp_flow_entry { - uint64_t swfe_cookie; - uint16_t swfe_priority; - uint8_t swfe_table_id; - struct ofp_match *swfe_match; - LIST_ENTRY(swofp_flow_entry) swfe_next; - uint64_t swfe_packet_cnt; - uint64_t swfe_byte_cnt; - struct ofp_instruction_goto_table *swfe_goto_table; - struct ofp_instruction_write_metadata *swfe_write_metadata; - struct ofp_instruction_actions *swfe_write_actions; - struct ofp_instruction_actions *swfe_apply_actions; - struct ofp_instruction_actions *swfe_clear_actions; - struct ofp_instruction_meter *swfe_meter; - struct ofp_instruction_experimenter *swfe_experimenter; - struct timespec swfe_installed_time; - struct timespec swfe_idle_time; - uint16_t swfe_idle_timeout; - uint16_t swfe_hard_timeout; - uint16_t swfe_flags; - int swfe_tablemiss; -}; - -struct swofp_flow_table { - uint32_t swft_table_id; - TAILQ_ENTRY(swofp_flow_table) swft_table_next; - uint64_t swft_lookup_count; - uint64_t swft_matched_count; - LIST_HEAD(, swofp_flow_entry) swft_flow_list; - uint32_t swft_flow_num; -}; - -struct swofp_group_entry { - uint32_t swge_group_id; - LIST_ENTRY(swofp_group_entry) swge_next; - uint64_t swge_packet_count; - uint64_t swge_byte_count; - uint32_t swge_ref_count; - uint8_t swge_type; - uint32_t swge_buckets_len; - struct ofp_bucket *swge_buckets; - struct ofp_bucket_counter *swge_bucket_counter; /* XXX */ - struct timespec swge_installed_time; -}; - -struct swofp_action_set { - uint16_t swas_type; - struct ofp_action_header *swas_action; -}; - -/* Same as total number of OFP_ACTION_ */ -#define SWOFP_ACTION_SET_MAX 18 -struct swofp_pipeline_desc { - uint32_t swpld_table_id; - uint64_t swpld_cookie; - uint64_t swpld_metadata; - struct switch_flow_classify *swpld_swfcl; - struct switch_flow_classify swpld_pre_swfcl; - struct switch_fwdp_queue swpld_fwdp_q; - struct swofp_action_set swpld_action_set[SWOFP_ACTION_SET_MAX]; - struct ofp_action_header *swpld_set_fields[OFP_XM_T_MAX]; - int swpld_tablemiss; -}; - -struct swofp_ofs { - /* There are parameters by OpenFlow */ - uint32_t swofs_xidnxt; - uint64_t swofs_datapath_id; - struct ofp_switch_config swofs_switch_config; - struct timeout swofs_flow_timeout; - uint32_t swofs_flow_max_entry; - TAILQ_HEAD(, swofp_flow_table) swofs_table_list; - uint32_t swofs_group_max_table; - int swofs_group_table_num; - LIST_HEAD(, swofp_group_entry) swofs_group_table; - int (*swofp_cp_init)(struct switch_softc *); -}; - -struct swofp_mpmsg { - struct mbuf *swmp_hdr; - struct mbuf_list swmp_body; -}; -#define SWOFP_MPMSG_MAX 0xffef - -typedef int (*ofp_msg_handler)(struct switch_softc *, struct mbuf *); - -void swofp_forward_ofs(struct switch_softc *, struct switch_flow_classify *, - struct mbuf *); - -int swofp_input(struct switch_softc *, struct mbuf *); -int swofp_output(struct switch_softc *, struct mbuf *); -void swofp_timer(void *); - -struct ofp_oxm_class - *swofp_lookup_oxm_handler(struct ofp_ox_match *); -ofp_msg_handler - swofp_lookup_msg_handler(uint8_t); -ofp_msg_handler - swofp_lookup_mpmsg_handler(uint16_t); -struct ofp_action_handler - *swofp_lookup_action_handler(uint16_t); -ofp_msg_handler - *swofp_flow_mod_lookup_handler(uint8_t); -struct swofp_pipeline_desc - *swofp_pipeline_desc_create(struct switch_flow_classify *); -void swofp_pipeline_desc_destroy(struct swofp_pipeline_desc *); -int swofp_flow_match_by_swfcl(struct ofp_match *, - struct switch_flow_classify *); -struct swofp_flow_entry - *swofp_flow_lookup(struct swofp_flow_table *, - struct switch_flow_classify *); - -/* - * Flow table - */ -struct swofp_flow_table - *swofp_flow_table_lookup(struct switch_softc *, uint16_t); -struct swofp_flow_table - *swofp_flow_table_add(struct switch_softc *, uint16_t); -int swofp_flow_table_delete(struct switch_softc *, uint16_t); -void swofp_flow_table_delete_all(struct switch_softc *); -void swofp_flow_delete_on_table_by_group(struct switch_softc *, - struct swofp_flow_table *, uint32_t); -void swofp_flow_delete_on_table(struct switch_softc *, - struct swofp_flow_table *, struct ofp_match *, uint16_t, - uint64_t, uint64_t cookie_mask, uint32_t, - uint32_t, int); - -/* - * Group table - */ -struct swofp_group_entry - *swofp_group_entry_lookup(struct switch_softc *, uint32_t); -int swofp_group_entry_add(struct switch_softc *, - struct swofp_group_entry *); -int swofp_group_entry_delete(struct switch_softc *, - struct swofp_group_entry *); -int swofp_group_entry_delete_all(struct switch_softc *); -int swofp_validate_buckets(struct switch_softc *, struct mbuf *, uint8_t, - uint16_t *, uint16_t *); - -/* - * Flow entry - */ -int swofp_flow_entry_put_instructions(struct switch_softc *, - struct mbuf *, struct swofp_flow_entry *, uint16_t *, uint16_t *); -void swofp_flow_entry_table_free(struct ofp_instruction **); -void swofp_flow_entry_instruction_free(struct swofp_flow_entry *); -void swofp_flow_entry_free(struct swofp_flow_entry **); -void swofp_flow_entry_add(struct switch_softc *, struct swofp_flow_table *, - struct swofp_flow_entry *); -void swofp_flow_entry_delete(struct switch_softc *, - struct swofp_flow_table *, struct swofp_flow_entry *, uint8_t); -int swofp_flow_mod_cmd_common_modify(struct switch_softc *, - struct mbuf *, int ); -int swofp_flow_cmp_non_strict(struct swofp_flow_entry *, - struct ofp_match *); -int swofp_flow_cmp_strict(struct swofp_flow_entry *, struct ofp_match *, - uint32_t); -int swofp_flow_cmp_common(struct swofp_flow_entry *, - struct ofp_match *, int); -struct swofp_flow_entry - *swofp_flow_search_by_table(struct swofp_flow_table *, - struct ofp_match *, uint16_t); -int swofp_flow_has_group(struct ofp_instruction_actions *, uint32_t); -int swofp_flow_filter_out_port(struct ofp_instruction_actions *, - uint32_t); -int swofp_flow_filter(struct swofp_flow_entry *, uint64_t, uint64_t, - uint32_t, uint32_t); -void swofp_flow_timeout(struct switch_softc *); -int swofp_validate_oxm(struct ofp_ox_match *, uint16_t *); -int swofp_validate_flow_match(struct ofp_match *, uint16_t *); -int swofp_validate_flow_instruction(struct switch_softc *, - struct ofp_instruction *, size_t, uint16_t *, uint16_t *); -int swofp_validate_action(struct switch_softc *sc, - struct ofp_action_header *, size_t, uint16_t *); - -/* - * OpenFlow protocol compare oxm - */ -int swofp_ox_cmp_data(struct ofp_ox_match *, - struct ofp_ox_match *, int); -int swofp_ox_cmp_ipv6_addr(struct ofp_ox_match *, - struct ofp_ox_match *, int); -int swofp_ox_cmp_ipv4_addr(struct ofp_ox_match *, - struct ofp_ox_match *, int); -int swofp_ox_cmp_vlan_vid(struct ofp_ox_match *, - struct ofp_ox_match *, int); -int swofp_ox_cmp_ether_addr(struct ofp_ox_match *, - struct ofp_ox_match *, int); -/* - * OpenFlow protocol match field handlers - */ -int swofp_ox_match_ether_addr(struct switch_flow_classify *, - struct ofp_ox_match *); -int swofp_ox_match_vlan_vid(struct switch_flow_classify *, - struct ofp_ox_match *); -int swofp_ox_match_ipv6_addr(struct switch_flow_classify *, - struct ofp_ox_match *); -int swofp_ox_match_ipv4_addr(struct switch_flow_classify *, - struct ofp_ox_match *); -int swofp_ox_match_uint8(struct switch_flow_classify *, - struct ofp_ox_match *); -int swofp_ox_match_uint16(struct switch_flow_classify *, - struct ofp_ox_match *); -int swofp_ox_match_uint32(struct switch_flow_classify *, - struct ofp_ox_match *); -int swofp_ox_match_uint64(struct switch_flow_classify *, - struct ofp_ox_match *); - -void swofp_ox_match_put_start(struct ofp_match *); -int swofp_ox_match_put_end(struct ofp_match *); -int swofp_ox_match_put_uint32(struct ofp_match *, uint8_t, uint32_t); -int swofp_ox_match_put_uint64(struct ofp_match *, uint8_t, uint64_t); -int swofp_nx_match_put(struct ofp_match *, uint8_t, int, caddr_t); - -/* - * OpenFlow protocol push/pop tag action handlers - */ -struct mbuf - *swofp_action_push_vlan(struct switch_softc *, struct mbuf *, - struct swofp_pipeline_desc *, struct ofp_action_header *); -struct mbuf - *swofp_action_pop_vlan(struct switch_softc *, struct mbuf *, - struct swofp_pipeline_desc *, struct ofp_action_header *); -struct mbuf - *swofp_expand_8021q_tag(struct mbuf *); - -/* - * OpenFlow protocol set field action handlers - */ -struct mbuf - *swofp_apply_set_field_udp(struct mbuf *, int, - struct switch_flow_classify *, struct switch_flow_classify *); -struct mbuf - *swofp_apply_set_field_tcp(struct mbuf *, int, - struct switch_flow_classify *, struct switch_flow_classify *); -struct mbuf - *swofp_apply_set_field_nd6(struct mbuf *, int, - struct switch_flow_classify *, struct switch_flow_classify *); -struct mbuf - *swofp_apply_set_field_icmpv6(struct mbuf *m, int, - struct switch_flow_classify *, struct switch_flow_classify *); -struct mbuf - *swofp_apply_set_field_icmpv4(struct mbuf *, int, - struct switch_flow_classify *, struct switch_flow_classify *); -struct mbuf - *swofp_apply_set_field_ipv6(struct mbuf *, int, - struct switch_flow_classify *, struct switch_flow_classify *); -struct mbuf - *swofp_apply_set_field_ipv4(struct mbuf *, int, - struct switch_flow_classify *, struct switch_flow_classify *); -struct mbuf - *swofp_apply_set_field_arp(struct mbuf *, int, - struct switch_flow_classify *, struct switch_flow_classify *); -struct mbuf - *swofp_apply_set_field_ether(struct mbuf *, int, - struct switch_flow_classify *, struct switch_flow_classify *); -struct mbuf - *swofp_apply_set_field_tunnel(struct mbuf *, int, - struct switch_flow_classify *, struct switch_flow_classify *); -struct mbuf - *swofp_apply_set_field(struct mbuf *, struct swofp_pipeline_desc *); -int swofp_ox_set_vlan_vid(struct switch_flow_classify *, - struct ofp_ox_match *); -int swofp_ox_set_uint8(struct switch_flow_classify *, - struct ofp_ox_match *); -int swofp_ox_set_uint16(struct switch_flow_classify *, - struct ofp_ox_match *); -int swofp_ox_set_uint32(struct switch_flow_classify *, - struct ofp_ox_match *); -int swofp_ox_set_uint64(struct switch_flow_classify *, - struct ofp_ox_match *); -int swofp_ox_set_ether_addr(struct switch_flow_classify *, - struct ofp_ox_match *); -int swofp_ox_set_ipv4_addr(struct switch_flow_classify *, - struct ofp_ox_match *); -int swofp_ox_set_ipv6_addr(struct switch_flow_classify *, - struct ofp_ox_match *); - -/* - * OpenFlow protocol execute action handlers - */ -int swofp_action_output_controller(struct switch_softc *, struct mbuf *, - struct swofp_pipeline_desc *, uint16_t, uint8_t); -struct mbuf - *swofp_action_output(struct switch_softc *, struct mbuf *, - struct swofp_pipeline_desc *, struct ofp_action_header *); -struct mbuf - *swofp_action_group_all(struct switch_softc *, struct mbuf *, - struct swofp_pipeline_desc *, struct swofp_group_entry *); -struct mbuf - *swofp_action_group(struct switch_softc *, struct mbuf *, - struct swofp_pipeline_desc *, struct ofp_action_header *); -struct mbuf - *swofp_action_set_field(struct switch_softc *, struct mbuf *, - struct swofp_pipeline_desc *, struct ofp_action_header *); -struct mbuf - *swofp_execute_action(struct switch_softc *, struct mbuf *, - struct swofp_pipeline_desc *, struct ofp_action_header *); -struct mbuf - *swofp_execute_action_set_field(struct switch_softc *, struct mbuf *, - struct swofp_pipeline_desc *, struct ofp_action_header *); -struct mbuf - *swofp_execute_action_set(struct switch_softc *, struct mbuf *, - struct swofp_pipeline_desc *); -struct mbuf - *swofp_apply_actions(struct switch_softc *, struct mbuf *, - struct swofp_pipeline_desc *, struct ofp_instruction_actions *); -struct swofp_action_set - *swofp_lookup_action_set(struct swofp_pipeline_desc *, uint16_t); -void swofp_write_actions_set_field(struct swofp_action_set *, - struct ofp_action_header *); -int swofp_write_actions(struct ofp_instruction_actions *, - struct swofp_pipeline_desc *); -void swofp_clear_actions_set_field(struct swofp_action_set *, - struct ofp_action_header *); -int swofp_clear_actions(struct ofp_instruction_actions *, - struct swofp_pipeline_desc *); -void swofp_write_metadata(struct ofp_instruction_write_metadata *, - struct swofp_pipeline_desc *); - -/* - * OpenFlow protocol message handlers - */ -void swofp_send_hello(struct switch_softc *); -int swofp_recv_hello(struct switch_softc *, struct mbuf *); -int swofp_send_echo(struct switch_softc *, struct mbuf *); -int swofp_recv_echo(struct switch_softc *, struct mbuf *); -void swofp_send_error(struct switch_softc *, struct mbuf *, - uint16_t, uint16_t); -int swofp_recv_features_req(struct switch_softc *, struct mbuf *); -int swofp_recv_config_req(struct switch_softc *, struct mbuf *); -int swofp_recv_set_config(struct switch_softc *, struct mbuf *); -int swofp_send_flow_removed(struct switch_softc *, - struct swofp_flow_entry *, uint8_t); -int swofp_recv_packet_out(struct switch_softc *, struct mbuf *); -int swofp_flow_mod_cmd_add(struct switch_softc *, struct mbuf *); -int swofp_flow_mod_cmd_common_modify(struct switch_softc *, - struct mbuf *, int); -int swofp_flow_mod_cmd_modify(struct switch_softc *, struct mbuf *); -int swofp_flow_mod_cmd_modify_strict(struct switch_softc *, struct mbuf *); -int swofp_flow_mod_cmd_common_delete(struct switch_softc *, - struct mbuf *, int); -int swofp_flow_mod_cmd_delete(struct switch_softc *, struct mbuf *); -int swofp_flow_mod_cmd_delete_strict(struct switch_softc *, struct mbuf *); -int swofp_flow_mod(struct switch_softc *, struct mbuf *); -int swofp_group_mod_add(struct switch_softc *, struct mbuf *); -int swofp_group_mod_modify(struct switch_softc *, struct mbuf *); -int swofp_group_mod_delete(struct switch_softc *, struct mbuf *); -int swofp_group_mod(struct switch_softc *, struct mbuf *); -int swofp_multipart_req(struct switch_softc *, struct mbuf *); -int swofp_barrier_req(struct switch_softc *, struct mbuf *); -void swofp_barrier_reply(struct switch_softc *, struct mbuf *); - -/* - * OpenFlow protocol multipart message handlers - */ -int swofp_mpmsg_reply_create(struct ofp_multipart *, struct swofp_mpmsg *); -int swofp_mpmsg_put(struct swofp_mpmsg *, caddr_t, size_t); -int swofp_mpmsg_m_put(struct swofp_mpmsg *, struct mbuf *); -void swofp_mpmsg_destroy(struct swofp_mpmsg *); -int swofp_multipart_reply(struct switch_softc *, struct swofp_mpmsg *); - -int swofp_put_flow(struct mbuf *, struct swofp_flow_table *, - struct swofp_flow_entry *); -int swofp_put_flows_from_table(struct swofp_mpmsg *, - struct swofp_flow_table *, struct ofp_flow_stats_request *); -void swofp_aggregate_stat_from_table(struct ofp_aggregate_stats *, - struct swofp_flow_table *, struct ofp_aggregate_stats_request *); -int swofp_table_features_put_oxm(struct mbuf *, int *, uint16_t); -int swofp_table_features_put_actions(struct mbuf *, int *, uint16_t); -int swofp_table_features_put_instruction(struct mbuf *, int *, uint16_t); - -int swofp_mp_recv_desc(struct switch_softc *, struct mbuf *); -int swofp_mp_recv_flow(struct switch_softc *, struct mbuf *); -int swofp_mp_recv_aggregate_flow_stat(struct switch_softc *, struct mbuf *); -int swofp_mp_recv_table_stats(struct switch_softc *, struct mbuf *); -int swofp_mp_recv_table_features(struct switch_softc *, struct mbuf *); -int swofp_mp_recv_port_stats(struct switch_softc *, struct mbuf *); -int swofp_mp_recv_port_desc(struct switch_softc *, struct mbuf *); -int swofp_mp_recv_group_desc(struct switch_softc *, struct mbuf *); - -/* - * OXM (OpenFlow Extensible Match) structures appear in ofp_match structure - * and ofp_instruction_{apply|write}_action structure. - */ -#define OFP_OXM_FOREACH(hdr, len, curr) \ -for ((curr) = (struct ofp_ox_match *)((caddr_t)(hdr) + sizeof(*hdr)); \ - (caddr_t)(curr) < ((caddr_t)(hdr) + (len)); \ - (curr) = (struct ofp_ox_match *)((caddr_t)(curr) + \ - (curr)->oxm_length + sizeof(*curr))) - -#define OFP_OXM_TERMINATED(hdr, len, curr) \ - (((caddr_t)(hdr) + (len)) <= (caddr_t)(curr)) - - -#define OFP_ACTION_FOREACH(head, len, curr) \ -/* struct ofp_action_header head, curr */ \ -for ((curr) = (head); (caddr_t)curr < ((caddr_t)head + (len)); \ - (curr) = (struct ofp_action_header *)((caddr_t)curr + \ - ntohs((curr)->ah_len))) - -/* - * Get instruction offset in ofp_flow_mod - */ -#define OFP_FLOW_MOD_MSG_INSTRUCTION_OFFSET(ofm) \ - (offsetof(struct ofp_flow_mod, fm_match) + \ - OFP_ALIGN(ntohs((ofm)->fm_match.om_length))) - -/* - * Instructions "FOREACH" in ofp_flow_mod. You can get header using - * OFP_FLOW_MOD_MSG_INSTRUCTION_PTR macro - */ -#define OFP_FLOW_MOD_INSTRUCTON_FOREACH(hadr, end, curr) \ -for ((curr) = (head); (caddr_t)curr < ((caddr_t)head + (end)); \ - (curr) = (struct ofp_instruction *)((caddr_t)(curr) + (curr)->i_len)) - - -#define OFP_I_ACTIONS_FOREACH(head, curr) \ -/* struct ofp_match head, struct ofp_ox_match curr */ \ -for ((curr) = (struct ofp_action_header *)((caddr_t)head + sizeof(*head)); \ - (caddr_t)curr < ((caddr_t)head + ntohs((head)->ia_len)); \ - (curr) = (struct ofp_action_header *)((caddr_t)curr + \ - ntohs((curr)->ah_len))) - -#define OFP_BUCKETS_FOREACH(head, end, curr) \ -for ((curr) = (head); (caddr_t)curr < ((caddr_t)head + (end)); \ - (curr) = (struct ofp_bucket *)((caddr_t)(curr) + ntohs((curr)->b_len))) - - -/* - * OpenFlow protocol message handlers - */ -struct ofp_msg_class { - uint8_t msg_type; - ofp_msg_handler msg_handler; -}; -struct ofp_msg_class ofp_msg_table[] = { - { OFP_T_HELLO, swofp_recv_hello }, - { OFP_T_ERROR, NULL /* unsupported */ }, - { OFP_T_ECHO_REQUEST, swofp_recv_echo }, - { OFP_T_ECHO_REPLY, NULL /* from switch */ }, - { OFP_T_EXPERIMENTER, NULL /* unsupported */ }, - { OFP_T_FEATURES_REQUEST, swofp_recv_features_req }, - { OFP_T_FEATURES_REPLY, NULL /* from switch */ }, - { OFP_T_GET_CONFIG_REQUEST, swofp_recv_config_req }, - { OFP_T_GET_CONFIG_REPLY, NULL /* from switch */ }, - { OFP_T_SET_CONFIG, swofp_recv_set_config }, - { OFP_T_PACKET_IN, NULL /* from switch */ }, - { OFP_T_FLOW_REMOVED, NULL /* from switch */ }, - { OFP_T_PORT_STATUS, NULL /* from switch */ }, - { OFP_T_PACKET_OUT, swofp_recv_packet_out }, - { OFP_T_FLOW_MOD, swofp_flow_mod }, - { OFP_T_GROUP_MOD, swofp_group_mod }, - { OFP_T_PORT_MOD, NULL /* unsupported */ }, - { OFP_T_TABLE_MOD, NULL /* unsupported */ }, - { OFP_T_MULTIPART_REQUEST, swofp_multipart_req }, - { OFP_T_MULTIPART_REPLY, NULL /* from switch */ }, - { OFP_T_BARRIER_REQUEST, swofp_barrier_req }, - { OFP_T_BARRIER_REPLY, NULL /* from switch */ }, - { OFP_T_QUEUE_GET_CONFIG_REQUEST, NULL /* unsupported */ }, - { OFP_T_QUEUE_GET_CONFIG_REPLY, NULL /* from switch */ }, - { OFP_T_ROLE_REQUEST, NULL /* unsupported */ }, - { OFP_T_ROLE_REPLY, NULL /* from switch */ }, - { OFP_T_GET_ASYNC_REQUEST, NULL /* unsupported */ }, - { OFP_T_GET_ASYNC_REPLY, NULL /* from switch */ }, - { OFP_T_SET_ASYNC, NULL /* unsupported */ }, - { OFP_T_METER_MOD, NULL /* unsupported */ } -}; - - -/* -* OpenFlow protocol modification flow message command handlers -*/ -struct ofp_flow_mod_class { - uint8_t ofm_cmd_type; - ofp_msg_handler ofm_cmd_handler; -}; -struct ofp_flow_mod_class ofp_flow_mod_table[] = { - { OFP_FLOWCMD_ADD, swofp_flow_mod_cmd_add }, - { OFP_FLOWCMD_MODIFY, swofp_flow_mod_cmd_modify }, - { OFP_FLOWCMD_MODIFY_STRICT, swofp_flow_mod_cmd_modify_strict }, - { OFP_FLOWCMD_DELETE, swofp_flow_mod_cmd_delete }, - { OFP_FLOWCMD_DELETE_STRICT, swofp_flow_mod_cmd_delete_strict }, -}; - -/* - * OpenFlow protocol multipart handlers - */ -struct ofp_mpmsg_class { - uint8_t msgsg_type; - ofp_msg_handler mpmsg_handler; -}; -struct ofp_mpmsg_class ofp_mpmsg_table[] = { - { OFP_MP_T_DESC, swofp_mp_recv_desc }, - { OFP_MP_T_FLOW, swofp_mp_recv_flow }, - { OFP_MP_T_AGGREGATE, swofp_mp_recv_aggregate_flow_stat }, - { OFP_MP_T_TABLE, swofp_mp_recv_table_stats }, - { OFP_MP_T_PORT_STATS, swofp_mp_recv_port_stats }, - { OFP_MP_T_QUEUE, NULL }, - { OFP_MP_T_GROUP, NULL }, - { OFP_MP_T_GROUP_DESC, swofp_mp_recv_group_desc }, - { OFP_MP_T_GROUP_FEATURES, NULL }, - { OFP_MP_T_METER, NULL }, - { OFP_MP_T_METER_CONFIG, NULL }, - { OFP_MP_T_METER_FEATURES, NULL }, - { OFP_MP_T_TABLE_FEATURES, swofp_mp_recv_table_features }, - { OFP_MP_T_PORT_DESC, swofp_mp_recv_port_desc } -}; - -/* - * OpenFlow OXM match handlers - */ -#define SWOFP_MATCH_MASK 0x1 -#define SWOFP_MATCH_WILDCARD 0x2 - -struct ofp_oxm_class { - uint8_t oxm_field; - uint8_t oxm_len; /* This length defined by specification */ - uint8_t oxm_flags; - int (*oxm_match)(struct switch_flow_classify *, - struct ofp_ox_match *); - int (*oxm_set)(struct switch_flow_classify *, - struct ofp_ox_match *); - int (*oxm_cmp)(struct ofp_ox_match *, - struct ofp_ox_match *, int); -}; - -/* - * Handlers for basic class for OpenFlow - */ -struct ofp_oxm_class ofp_oxm_handlers[] = { - { - OFP_XM_T_IN_PORT, - sizeof(uint32_t), - 0, - swofp_ox_match_uint32, NULL, - swofp_ox_cmp_data - }, - { - OFP_XM_T_IN_PHY_PORT, - sizeof(uint32_t), - 0, - NULL, NULL, - NULL - }, - { - OFP_XM_T_META, - sizeof(uint64_t), - SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD, - swofp_ox_match_uint64, NULL, - NULL - }, - { - OFP_XM_T_ETH_DST, - ETHER_ADDR_LEN, - SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD, - swofp_ox_match_ether_addr, swofp_ox_set_ether_addr, - swofp_ox_cmp_ether_addr - }, - { - OFP_XM_T_ETH_SRC, - ETHER_ADDR_LEN, - SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD, - swofp_ox_match_ether_addr, swofp_ox_set_ether_addr, - swofp_ox_cmp_ether_addr - }, - { - OFP_XM_T_ETH_TYPE, - sizeof(uint16_t), - SWOFP_MATCH_WILDCARD, - swofp_ox_match_uint16, swofp_ox_set_uint16, - swofp_ox_cmp_data - }, - { - OFP_XM_T_VLAN_VID, - sizeof(uint16_t), - SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD, - swofp_ox_match_vlan_vid, swofp_ox_set_vlan_vid, - swofp_ox_cmp_vlan_vid - }, - { - OFP_XM_T_VLAN_PCP, - sizeof(uint8_t), - SWOFP_MATCH_WILDCARD, - swofp_ox_match_uint8, swofp_ox_set_uint16, - swofp_ox_cmp_data - }, - { - OFP_XM_T_IP_DSCP, - sizeof(uint8_t), - SWOFP_MATCH_WILDCARD, - swofp_ox_match_uint8, swofp_ox_set_uint8, - swofp_ox_cmp_data - }, - { - OFP_XM_T_IP_ECN, - sizeof(uint8_t), - SWOFP_MATCH_WILDCARD, - swofp_ox_match_uint8, swofp_ox_set_uint8, - swofp_ox_cmp_data - }, - { - OFP_XM_T_IP_PROTO, - sizeof(uint8_t), - SWOFP_MATCH_WILDCARD, - swofp_ox_match_uint8, swofp_ox_set_uint8, - swofp_ox_cmp_data - }, - { - OFP_XM_T_IPV4_SRC, - sizeof(uint32_t), - SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD, - swofp_ox_match_ipv4_addr, swofp_ox_set_ipv4_addr, - swofp_ox_cmp_ipv4_addr - }, - { - OFP_XM_T_IPV4_DST, - sizeof(uint32_t), - SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD, - swofp_ox_match_ipv4_addr, swofp_ox_set_ipv4_addr, - swofp_ox_cmp_ipv4_addr - }, - { - OFP_XM_T_TCP_SRC, - sizeof(uint16_t), - SWOFP_MATCH_WILDCARD, - swofp_ox_match_uint16, swofp_ox_set_uint16, - swofp_ox_cmp_data - }, - { - OFP_XM_T_TCP_DST, - sizeof(uint16_t), - SWOFP_MATCH_WILDCARD, - swofp_ox_match_uint16, swofp_ox_set_uint16, - swofp_ox_cmp_data - }, - { - OFP_XM_T_UDP_SRC, - sizeof(uint16_t), - SWOFP_MATCH_WILDCARD, - swofp_ox_match_uint16, swofp_ox_set_uint16, - swofp_ox_cmp_data - }, - { - OFP_XM_T_UDP_DST, - sizeof(uint16_t), - SWOFP_MATCH_WILDCARD, - swofp_ox_match_uint16, swofp_ox_set_uint16, - swofp_ox_cmp_data - }, - { - OFP_XM_T_SCTP_SRC, - sizeof(uint16_t), - SWOFP_MATCH_WILDCARD, - swofp_ox_match_uint16, swofp_ox_set_uint16, - swofp_ox_cmp_data - }, - { - OFP_XM_T_SCTP_DST, - sizeof(uint16_t), - SWOFP_MATCH_WILDCARD, - swofp_ox_match_uint16, swofp_ox_set_uint16, - swofp_ox_cmp_data - }, - { - OFP_XM_T_ICMPV4_TYPE, - sizeof(uint8_t), - SWOFP_MATCH_WILDCARD, - swofp_ox_match_uint8, swofp_ox_set_uint8, - swofp_ox_cmp_data - }, - { - OFP_XM_T_ICMPV4_CODE, - sizeof(uint8_t), - SWOFP_MATCH_WILDCARD, - swofp_ox_match_uint8, swofp_ox_set_uint8, - swofp_ox_cmp_data - }, - { - OFP_XM_T_ARP_OP, - sizeof(uint16_t), - SWOFP_MATCH_WILDCARD, - swofp_ox_match_uint16, swofp_ox_set_uint16, - swofp_ox_cmp_data - }, - { - OFP_XM_T_ARP_SPA, - sizeof(uint32_t), - SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD, - swofp_ox_match_ipv4_addr, swofp_ox_set_ipv4_addr, - swofp_ox_cmp_ipv4_addr - }, - { - OFP_XM_T_ARP_TPA, - sizeof(uint32_t), - SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD, - swofp_ox_match_ipv4_addr, swofp_ox_set_ipv4_addr, - swofp_ox_cmp_ipv4_addr - }, - { - OFP_XM_T_ARP_SHA, - ETHER_ADDR_LEN, - SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD, - swofp_ox_match_ether_addr, swofp_ox_set_ether_addr, - swofp_ox_cmp_ether_addr - }, - { - OFP_XM_T_ARP_THA, - ETHER_ADDR_LEN, - SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD, - swofp_ox_match_ether_addr, swofp_ox_set_ether_addr, - swofp_ox_cmp_ether_addr - }, -#ifdef INET6 - { - OFP_XM_T_IPV6_SRC, - sizeof(struct in6_addr), - SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD, - swofp_ox_match_ipv6_addr, swofp_ox_set_ipv6_addr, - swofp_ox_cmp_ipv6_addr - }, - { - OFP_XM_T_IPV6_DST, - sizeof(struct in6_addr), - SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD, - swofp_ox_match_ipv6_addr, swofp_ox_set_ipv6_addr, - swofp_ox_cmp_ipv6_addr - }, - { - OFP_XM_T_IPV6_FLABEL, - sizeof(uint32_t), - SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD, - swofp_ox_match_uint32, swofp_ox_set_uint32, - swofp_ox_cmp_data - }, - { - OFP_XM_T_ICMPV6_TYPE, - sizeof(uint8_t), - SWOFP_MATCH_WILDCARD, - swofp_ox_match_uint8, swofp_ox_set_uint8, - swofp_ox_cmp_data - }, - { - OFP_XM_T_ICMPV6_CODE, - sizeof(uint8_t), - SWOFP_MATCH_WILDCARD, - swofp_ox_match_uint8, swofp_ox_set_uint8, - swofp_ox_cmp_data - }, - { - OFP_XM_T_IPV6_ND_TARGET, - sizeof(struct in6_addr), - SWOFP_MATCH_WILDCARD, - swofp_ox_match_ipv6_addr, swofp_ox_set_ipv6_addr, - swofp_ox_cmp_ipv6_addr - }, - { - OFP_XM_T_IPV6_ND_SLL, - ETHER_ADDR_LEN, - SWOFP_MATCH_WILDCARD, - swofp_ox_match_ether_addr, swofp_ox_set_ether_addr, - swofp_ox_cmp_ether_addr - }, - { - OFP_XM_T_IPV6_ND_TLL, - ETHER_ADDR_LEN, - SWOFP_MATCH_WILDCARD, - swofp_ox_match_ether_addr, swofp_ox_set_ether_addr, - swofp_ox_cmp_ether_addr - }, -#endif /* INET6 */ - { - OFP_XM_T_MPLS_LABEL, - sizeof(uint32_t), - SWOFP_MATCH_WILDCARD, - NULL, NULL, - NULL - }, - { - OFP_XM_T_MPLS_TC, - sizeof(uint8_t), - SWOFP_MATCH_WILDCARD, - NULL, NULL, - NULL - }, - { - OFP_XM_T_MPLS_BOS, - sizeof(uint8_t), - SWOFP_MATCH_WILDCARD, - NULL, NULL, - NULL - }, - { - OFP_XM_T_PBB_ISID, - 3, - SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD, - NULL, NULL, - NULL - }, - { - OFP_XM_T_TUNNEL_ID, - sizeof(uint64_t), - SWOFP_MATCH_WILDCARD, - swofp_ox_match_uint64, swofp_ox_set_uint64, - swofp_ox_cmp_data - }, - { - OFP_XM_T_IPV6_EXTHDR, - sizeof(uint16_t), - SWOFP_MATCH_WILDCARD, - NULL, NULL, - NULL - }, -}; - -/* - * Handlers for backward compatibility with NXM - */ -struct ofp_oxm_class ofp_oxm_nxm_handlers[] = { - { - OFP_XM_NXMT_TUNNEL_ID, - sizeof(uint64_t), - SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD, - swofp_ox_match_uint64, swofp_ox_set_uint64, - swofp_ox_cmp_data - }, - { - OFP_XM_NXMT_TUNNEL_IPV4_SRC, - sizeof(uint32_t), - SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD, - swofp_ox_match_ipv4_addr, swofp_ox_set_ipv4_addr, - swofp_ox_cmp_ipv4_addr - }, - { - OFP_XM_NXMT_TUNNEL_IPV4_DST, - sizeof(uint32_t), - SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD, - swofp_ox_match_ipv4_addr, swofp_ox_set_ipv4_addr, - swofp_ox_cmp_ipv4_addr - }, -#ifdef INET6 - { - OFP_XM_NXMT_TUNNEL_IPV6_SRC, - sizeof(struct in6_addr), - SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD, - swofp_ox_match_ipv6_addr, swofp_ox_set_ipv6_addr, - swofp_ox_cmp_ipv6_addr - }, - { - OFP_XM_NXMT_TUNNEL_IPV6_DST, - sizeof(struct in6_addr), - SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD, - swofp_ox_match_ipv6_addr, swofp_ox_set_ipv6_addr, - swofp_ox_cmp_ipv6_addr - }, -#endif /* INET6 */ -}; - -/* - * OpenFlow action handlers - */ -struct ofp_action_handler { - uint16_t action_type; - struct mbuf * (*action)(struct switch_softc *, struct mbuf *, - struct swofp_pipeline_desc *, struct ofp_action_header *); -}; -struct ofp_action_handler ofp_action_handlers[] = { - /* - * Following order complies with action set order in - * OpenFlow Switch Specification (ver. 1.3.5) - */ - { - OFP_ACTION_COPY_TTL_IN, - NULL - }, - { - OFP_ACTION_POP_MPLS, - NULL - }, - { - OFP_ACTION_POP_PBB, - NULL - }, - { - OFP_ACTION_POP_VLAN, - swofp_action_pop_vlan - }, - { - OFP_ACTION_PUSH_MPLS, - NULL - }, - { - OFP_ACTION_PUSH_PBB, - NULL - }, - { - OFP_ACTION_PUSH_VLAN, - swofp_action_push_vlan - }, - { - OFP_ACTION_COPY_TTL_OUT, - NULL - }, - { - OFP_ACTION_DEC_NW_TTL, - NULL - }, - { - OFP_ACTION_DEC_MPLS_TTL, - NULL - }, - { - OFP_ACTION_SET_MPLS_TTL, - NULL - }, - { - OFP_ACTION_SET_NW_TTL, - NULL - }, - { - OFP_ACTION_SET_FIELD, - swofp_action_set_field - }, - { - OFP_ACTION_SET_QUEUE, - NULL - }, - { - OFP_ACTION_GROUP, - swofp_action_group - }, - { - OFP_ACTION_OUTPUT, - swofp_action_output - }, - { - OFP_ACTION_EXPERIMENTER, - NULL - }, /* XXX Where is best position? */ -}; - -extern struct pool swfcl_pool; -struct pool swpld_pool; - -void -swofp_attach(void) -{ - pool_init(&swpld_pool, sizeof(struct swofp_pipeline_desc), 0, 0, 0, - "swpld", NULL); -} - - -int -swofp_create(struct switch_softc *sc) -{ - struct swofp_ofs *swofs; - int error; - - swofs = malloc(sizeof(*swofs), M_DEVBUF, M_NOWAIT|M_ZERO); - if (swofs == NULL) - return (ENOMEM); - - sc->sc_ofs = swofs; - - TAILQ_INIT(&swofs->swofs_table_list); - - /* - * A table with id 0 must exist - */ - if ((swofp_flow_table_add(sc, 0)) == NULL) { - error = ENOBUFS; - free(swofs, M_DEVBUF, sizeof(*swofs)); - return (error); - } - - swofs->swofs_xidnxt = 1; - arc4random_buf(&swofs->swofs_datapath_id, - sizeof(swofs->swofs_datapath_id)); - - timeout_set(&swofs->swofs_flow_timeout, swofp_timer, sc); - timeout_add_sec(&swofs->swofs_flow_timeout, 10); - - /* TODO: Configured from ifconfig */ - swofs->swofs_group_max_table = 1000; - swofs->swofs_flow_max_entry = 10000; - - sc->sc_capabilities |= SWITCH_CAP_OFP; - sc->switch_process_forward = swofp_forward_ofs; - -#if NBPFILTER > 0 - bpfattach(&sc->sc_ofbpf, &sc->sc_if, DLT_OPENFLOW, - sizeof(struct ofp_header)); -#endif - - return (0); -} - -void -swofp_destroy(struct switch_softc *sc) -{ - struct swofp_ofs *swofs = sc->sc_ofs; - - if ((sc->sc_capabilities & SWITCH_CAP_OFP) == 0 || swofs == NULL) - return; - - timeout_del(&swofs->swofs_flow_timeout); - - sc->sc_capabilities &= ~SWITCH_CAP_OFP; - sc->switch_process_forward = NULL; - - swofp_group_entry_delete_all(sc); - - free(swofs, M_DEVBUF, sizeof(*swofs)); -} - -int -swofp_init(struct switch_softc *sc) -{ - sc->sc_swdev->swdev_input = swofp_input; - swofp_send_hello(sc); - return (0); -} - -uint32_t -swofp_assign_portno(struct switch_softc *sc, uint32_t req) -{ - struct switch_port *swpo; - uint32_t candidate; - - TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) { - if (swpo->swpo_port_no == req) - break; - } - if (swpo == NULL) - return (req); - - /* XXX - * OS's ifindex is "short", so it expect that floowing is unique - */ - candidate = (req << 16) | req; - while (1) { - TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) { - if (swpo->swpo_port_no == candidate) - break; - } - if (swpo == NULL) - return (candidate); - - if (candidate < OFP_PORT_MAX) - candidate++; - else - candidate = 0; - } -} - -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) - break; - memcpy(&swofs->swofs_datapath_id, &bparam->ifbrp_datapath, - sizeof(uint64_t)); - break; - case SIOCSWGMAXFLOW: - bparam->ifbrp_maxflow = swofs->swofs_flow_max_entry; - break; - case SIOCSWGMAXGROUP: - bparam->ifbrp_maxgroup = swofs->swofs_group_max_table; - break; - case SIOCSWSPORTNO: - if ((error = suser(curproc)) != 0) - break; - - if (breq->ifbr_portno >= OFP_PORT_MAX) - return (EINVAL); - - if ((ifs = if_unit(breq->ifbr_ifsname)) == NULL) - return (ENOENT); - - if (ifs->if_switchport == NULL) { - if_put(ifs); - return (ENOENT); - } - - TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) { - if (swpo->swpo_port_no == breq->ifbr_portno) { - if_put(ifs); - return (EEXIST); - } - } - - swpo = (struct switch_port *)ifs->if_switchport; - if_put(ifs); - swpo->swpo_port_no = breq->ifbr_portno; - - break; - default: - error = ENOTTY; - break; - } - - return (error); -} - -/* TODO: Optimization */ -struct ofp_oxm_class * -swofp_lookup_oxm_handler(struct ofp_ox_match *oxm) -{ - struct ofp_oxm_class *handlers; - uint8_t oxm_field; - int i, len; - - switch (ntohs(oxm->oxm_class)) { - case OFP_OXM_C_OPENFLOW_BASIC: - handlers = ofp_oxm_handlers; - len = nitems(ofp_oxm_handlers); - break; - case OFP_OXM_C_NXM_1: - handlers = ofp_oxm_nxm_handlers; - len = nitems(ofp_oxm_nxm_handlers); - break; - default: - return (NULL); - } - - oxm_field = OFP_OXM_GET_FIELD(oxm); - - for (i = 0; i < len ; i++) { - if (handlers[i].oxm_field == oxm_field) - return (&handlers[i]); - } - - return (NULL); -} - -ofp_msg_handler -swofp_lookup_msg_handler(uint8_t type) -{ - if (type >= OFP_T_TYPE_MAX) - return (NULL); - else - return (ofp_msg_table[type].msg_handler); -} - -ofp_msg_handler -swofp_lookup_mpmsg_handler(uint16_t type) -{ - if (type >= nitems(ofp_mpmsg_table)) - return (NULL); - else - return (ofp_mpmsg_table[type].mpmsg_handler); -} - -struct ofp_action_handler * -swofp_lookup_action_handler(uint16_t type) -{ - int i; - - for (i = 0; i < nitems(ofp_action_handlers); i++) { - if (ofp_action_handlers[i].action_type == type) - return &(ofp_action_handlers[i]); - } - - return (NULL); -} - -struct swofp_pipeline_desc * -swofp_pipeline_desc_create(struct switch_flow_classify *swfcl) -{ - struct swofp_pipeline_desc *swpld = NULL; - struct swofp_action_set *swas = NULL; - int i; - - swpld = pool_get(&swpld_pool, PR_NOWAIT|PR_ZERO); - if (swpld == NULL) - return (NULL); - - /* - * ofp_action_handlers is sorted by applying action-set order, - * so it can be used for initializer for action-set. - */ - swas = swpld->swpld_action_set; - for (i = 0; i < nitems(ofp_action_handlers); i++) { - swas[i].swas_type = ofp_action_handlers[i].action_type; - if (swas[i].swas_type == OFP_ACTION_SET_FIELD) - swas[i].swas_action = (struct ofp_action_header *) - swpld->swpld_set_fields; - else - swas[i].swas_action = NULL; - } - - swpld->swpld_swfcl = swfcl; - - return (swpld); -} - -void -swofp_pipeline_desc_destroy(struct swofp_pipeline_desc *swpld) -{ - switch_swfcl_free(&swpld->swpld_pre_swfcl); - pool_put(&swpld_pool, swpld); -} - -struct swofp_flow_table * -swofp_flow_table_lookup(struct switch_softc *sc, uint16_t table_id) -{ - struct swofp_ofs *ofs = sc->sc_ofs; - struct swofp_flow_table *swft; - - TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) { - if (swft->swft_table_id == table_id) - return (swft); - } - - return (NULL); -} - -struct swofp_flow_table * -swofp_flow_table_add(struct switch_softc *sc, uint16_t table_id) -{ - struct swofp_ofs *ofs = sc->sc_ofs; - struct swofp_flow_table *swft, *new; - - if ((swft = swofp_flow_table_lookup(sc, table_id)) != NULL) - return (swft); - - if ((new = malloc(sizeof(*new), M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) - return (NULL); - - new->swft_table_id = table_id; - TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) { - if (table_id < swft->swft_table_id) - break; - } - - if (swft) - TAILQ_INSERT_BEFORE(swft, new, swft_table_next); - else - TAILQ_INSERT_TAIL(&ofs->swofs_table_list, new, swft_table_next); - - DPRINTF(sc, "add openflow flow table (id:%d)\n", table_id); - - return (new); -} - -int -swofp_flow_table_delete(struct switch_softc *sc, uint16_t table_id) -{ - struct swofp_ofs *ofs = sc->sc_ofs; - struct swofp_flow_table *swft; - struct swofp_flow_entry *swfe, *tswfe; - - if ((swft = swofp_flow_table_lookup(sc, table_id)) == NULL) - return ENOENT; - - LIST_FOREACH_SAFE(swfe, &swft->swft_flow_list, swfe_next, tswfe) { - /* - * Flows are deleted force because of deleting table, - * s it's not necessary to send flow remove message. - */ - swfe->swfe_flags &= ~(OFP_FLOWFLAG_SEND_FLOW_REMOVED); - swofp_flow_entry_delete(sc, swft, swfe, - OFP_FLOWREM_REASON_DELETE); - } - - TAILQ_REMOVE(&ofs->swofs_table_list, swft, swft_table_next); - free(swft, M_DEVBUF, sizeof(*swft)); - - DPRINTF(sc, "delete flow table (id:%d)\n", table_id); - - return 0; -} - -void -swofp_flow_table_delete_all(struct switch_softc *sc) -{ - struct swofp_ofs *ofs = sc->sc_ofs; - struct swofp_flow_table *swft, *tswft; - int error; - - TAILQ_FOREACH_SAFE(swft, &ofs->swofs_table_list, - swft_table_next, tswft) { - if ((error = swofp_flow_table_delete(sc,swft->swft_table_id))) - log(LOG_ERR, "can't delete table id:%d (error:%d)\n", - swft->swft_table_id, error); - } -} - -struct swofp_group_entry * -swofp_group_entry_lookup(struct switch_softc *sc, uint32_t group_id) -{ - struct swofp_ofs *ofs = sc->sc_ofs; - struct swofp_group_entry *swge; - - LIST_FOREACH(swge, &ofs->swofs_group_table, swge_next) { - if (swge->swge_group_id == group_id) - return swge; - } - - return (NULL); -} - -int -swofp_group_entry_add(struct switch_softc *sc, struct swofp_group_entry *swge) -{ - struct swofp_ofs *ofs = sc->sc_ofs; - - LIST_INSERT_HEAD(&ofs->swofs_group_table, swge, swge_next); - ofs->swofs_group_table_num++; - - DPRINTF(sc, "add group %d in group table (total %d)\n", - swge->swge_group_id, ofs->swofs_group_table_num); - - return (0); -} - -int -swofp_group_entry_delete(struct switch_softc *sc, - struct swofp_group_entry *swge) -{ - struct swofp_ofs *ofs = sc->sc_ofs; - struct swofp_flow_table *swft; - - DPRINTF(sc, "delete group %d in group table (total %d)\n", - swge->swge_group_id, ofs->swofs_group_table_num); - - LIST_REMOVE(swge, swge_next); - ofs->swofs_group_table_num--; - - TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) { - swofp_flow_delete_on_table_by_group(sc, swft, - swge->swge_group_id); - } - - free(swge->swge_buckets, M_DEVBUF, swge->swge_buckets_len); - free(swge, M_DEVBUF, sizeof(*swge)); - - return (0); -} - -int -swofp_group_entry_delete_all(struct switch_softc *sc) -{ - struct swofp_ofs *ofs = sc->sc_ofs; - struct swofp_group_entry *swge, *tswge; - - LIST_FOREACH_SAFE(swge, &ofs->swofs_group_table, swge_next, tswge) { - swofp_group_entry_delete(sc, swge); - } - - return (0); -} - -int -swofp_validate_buckets(struct switch_softc *sc, struct mbuf *m, uint8_t type, - uint16_t *etype, uint16_t *error) -{ - struct ofp_group_mod *ogm; - struct ofp_bucket *bucket; - struct ofp_action_header *ah; - uint16_t weight, remaining; - int start, len, off, num; - size_t blen; - - *etype = OFP_ERRTYPE_GROUP_MOD_FAILED; - - ogm = mtod(m, struct ofp_group_mod *); - start = offsetof(struct ofp_group_mod, gm_buckets); - remaining = len = ntohs(ogm->gm_oh.oh_length) - start; - - /* Invalid packet size. */ - if (len < 0) { - *error = OFP_ERRGROUPMOD_INVALID_GROUP; - return (-1); - } - - /* Indirect group type must always have one bucket. */ - if (len < sizeof(*bucket) && type == OFP_GROUP_T_INDIRECT) { - *error = OFP_ERRGROUPMOD_INVALID_GROUP; - return (-1); - } - - for (off = start, num = 0; off < start + len; off += blen, num++) { - bucket = (struct ofp_bucket *)(mtod(m, caddr_t) + off); - - blen = ntohs(bucket->b_len); - if (blen < sizeof(*bucket)) { - *error = OFP_ERRGROUPMOD_BAD_BUCKET; - return (-1); - } - - /* Validate that the bucket is smaller than the payload. */ - if (blen > remaining) { - *etype = OFP_ERRTYPE_BAD_REQUEST; - *error = OFP_ERRREQ_BAD_LEN; - return (-1); - } - remaining -= blen; - - /* - * Validate weight - */ - switch (type) { - case OFP_GROUP_T_ALL: - case OFP_GROUP_T_INDIRECT: - case OFP_GROUP_T_FAST_FAILOVER: - if (ntohs(bucket->b_weight) != 0) { - *error = OFP_ERRGROUPMOD_BAD_BUCKET; - return (-1); - } - break; - case OFP_GROUP_T_SELECT: - if (num > 1 && weight != ntohs(bucket->b_weight)) { - *error = OFP_ERRGROUPMOD_WEIGHT_UNSUPP; - return (-1); - } - break; - } - - /* - * INDIRECT type has only one bucket - */ - if (type == OFP_GROUP_T_INDIRECT && num > 1) { - *error = OFP_ERRGROUPMOD_BAD_BUCKET; - return (-1); - } - - weight = ntohs(bucket->b_weight); - - /* Skip if there are no actions to validate. */ - if (blen == sizeof(*bucket)) - continue; - - ah = (struct ofp_action_header *) - (mtod(m, caddr_t) + off + sizeof(*bucket)); - if (swofp_validate_action(sc, ah, blen - sizeof(*bucket), - error)) { - *etype = OFP_ERRTYPE_BAD_ACTION; - return (-1); - } - } - - return (0); -} - -void -swofp_flow_entry_table_free(struct ofp_instruction **table) -{ - if (*table) { - free(*table, M_DEVBUF, ntohs((*table)->i_len)); - *table = NULL; - } -} - -void -swofp_flow_entry_instruction_free(struct swofp_flow_entry *swfe) -{ - swofp_flow_entry_table_free((struct ofp_instruction **) - &swfe->swfe_goto_table); - swofp_flow_entry_table_free((struct ofp_instruction **) - &swfe->swfe_write_metadata); - swofp_flow_entry_table_free((struct ofp_instruction **) - &swfe->swfe_apply_actions); - swofp_flow_entry_table_free((struct ofp_instruction **) - &swfe->swfe_write_actions); - swofp_flow_entry_table_free((struct ofp_instruction **) - &swfe->swfe_clear_actions); - swofp_flow_entry_table_free((struct ofp_instruction **) - &swfe->swfe_experimenter); - swofp_flow_entry_table_free((struct ofp_instruction **) - &swfe->swfe_meter); -} - -void -swofp_flow_entry_free(struct swofp_flow_entry **swfe) -{ - if ((*swfe)->swfe_match) - free((*swfe)->swfe_match, M_DEVBUF, - ntohs((*swfe)->swfe_match->om_length)); - - swofp_flow_entry_instruction_free(*swfe); - - free((*swfe), M_DEVBUF, sizeof(**swfe)); -} - -void -swofp_flow_entry_add(struct switch_softc *sc, struct swofp_flow_table *swft, - struct swofp_flow_entry *swfe) -{ - swfe->swfe_table_id = swft->swft_table_id; - LIST_INSERT_HEAD(&swft->swft_flow_list, swfe, swfe_next); - swft->swft_flow_num++; - - DPRINTF(sc, "add flow in table %d (total %d)\n", - swft->swft_table_id, swft->swft_flow_num); -} - -void -swofp_flow_entry_delete(struct switch_softc *sc, struct swofp_flow_table *swft, - struct swofp_flow_entry *swfe, uint8_t reason) -{ - if (swfe->swfe_flags & OFP_FLOWFLAG_SEND_FLOW_REMOVED) - swofp_send_flow_removed(sc, swfe, reason); - - LIST_REMOVE(swfe, swfe_next); - swofp_flow_entry_free(&swfe); - swft->swft_flow_num--; - - DPRINTF(sc, "delete flow from table %d (total %d)\n", - swft->swft_table_id, swft->swft_flow_num); -} - -void -swofp_flow_timeout(struct switch_softc *sc) -{ - struct swofp_ofs *ofs = sc->sc_ofs; - struct swofp_flow_table *swft; - struct swofp_flow_entry *swfe, *tswfe; - struct timespec now, duration, idle; - - nanouptime(&now); - - TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) { - LIST_FOREACH_SAFE(swfe, &swft->swft_flow_list, - swfe_next, tswfe) { - if (swfe->swfe_idle_timeout) { - timespecsub(&now, &swfe->swfe_idle_time, &idle); - if (swfe->swfe_idle_timeout < idle.tv_sec) { - DPRINTF(sc, "flow expired " - "by idle timeout\n"); - swofp_flow_entry_delete(sc, swft, swfe, - OFP_FLOWREM_REASON_IDLE_TIMEOUT); - continue; - } - } - if (swfe->swfe_hard_timeout) { - timespecsub(&now, &swfe->swfe_installed_time, - &duration); - if (swfe->swfe_hard_timeout < duration.tv_sec) { - DPRINTF(sc, "flow expired " - "by hard timeout\n"); - swofp_flow_entry_delete(sc, swft, swfe, - OFP_FLOWREM_REASON_HARD_TIMEOUT); - } - } - } - } -} - -void -swofp_timer(void *v) -{ - struct switch_softc *sc = (struct switch_softc *)v; - struct swofp_ofs *swofs = sc->sc_ofs; - - swofp_flow_timeout(sc); - timeout_add_sec(&swofs->swofs_flow_timeout, 10); -} - -int -swofp_ox_cmp_data(struct ofp_ox_match *target, - struct ofp_ox_match *key, int strict) -{ - uint64_t tmth, tmask, kmth, kmask; - uint64_t dummy_mask = UINT64_MAX; - int len; - - if (OFP_OXM_GET_FIELD(target) != OFP_OXM_GET_FIELD(key)) - return (1); - - switch (OFP_OXM_GET_FIELD(target)) { - case OFP_XM_T_VLAN_PCP: - case OFP_XM_T_IP_DSCP: - case OFP_XM_T_IP_ECN: - case OFP_XM_T_IP_PROTO: - case OFP_XM_T_ICMPV4_CODE: - case OFP_XM_T_ICMPV4_TYPE: - case OFP_XM_T_ICMPV6_CODE: - case OFP_XM_T_ICMPV6_TYPE: - len = sizeof(uint8_t); - break; - case OFP_XM_T_ETH_TYPE: - case OFP_XM_T_TCP_SRC: - case OFP_XM_T_TCP_DST: - case OFP_XM_T_UDP_SRC: - case OFP_XM_T_UDP_DST: - case OFP_XM_T_ARP_OP: - len = sizeof(uint16_t); - break; - case OFP_XM_T_IN_PORT: - case OFP_XM_T_IPV6_FLABEL: - len = sizeof(uint32_t); - break; - case OFP_XM_T_TUNNEL_ID: /* alias OFP_XM_NXMT_TUNNEL_ID */ - len = sizeof(uint64_t); - break; - default: - return (1); - } - - tmth = tmask = kmth = kmask = 0; - - memcpy(&tmth, ((caddr_t)target + sizeof(*target)), len); - if (OFP_OXM_GET_HASMASK(target)) - memcpy(&tmask, ((caddr_t)target + sizeof(*target) + len), len); - else - memcpy(&tmask, &dummy_mask, len); - - memcpy(&kmth, ((caddr_t)key + sizeof(*key)), len); - if (OFP_OXM_GET_HASMASK(key)) - memcpy(&kmask, ((caddr_t)key + sizeof(*key) + len), len); - else - memcpy(&kmask, &dummy_mask, len); - - if (strict) { - if (tmask != kmask) - return (1); - } else { - if ((tmask & kmask) != kmask) - return (1); - } - - return !((tmth & tmask) == (kmth & kmask)); -} - -#ifdef INET6 -int -swofp_ox_cmp_ipv6_addr(struct ofp_ox_match *target, - struct ofp_ox_match *key, int strict) -{ - struct in6_addr tmth, tmask, kmth, kmask; - struct in6_addr mask = in6mask128; - - if (OFP_OXM_GET_FIELD(target) != OFP_OXM_GET_FIELD(key)) - return (1); - - switch (OFP_OXM_GET_FIELD(target)) { - case OFP_XM_NXMT_TUNNEL_IPV6_SRC: - case OFP_XM_NXMT_TUNNEL_IPV6_DST: - case OFP_XM_T_IPV6_SRC: - case OFP_XM_T_IPV6_DST: - case OFP_XM_T_IPV6_ND_TARGET: - break; - default: - return (1); - } - - memcpy(&kmth, ((caddr_t)key + sizeof(*key)), sizeof(kmth)); - if (OFP_OXM_GET_HASMASK(key)) - memcpy(&kmask, ((caddr_t)key + sizeof(*key) + sizeof(kmask)), - sizeof(kmask)); - else - kmask = mask; - - memcpy(&tmth, ((caddr_t)target + sizeof(*target)), sizeof(tmth)); - if (OFP_OXM_GET_HASMASK(target)) - memcpy(&tmask, ((caddr_t)target + sizeof(*target) + - sizeof(tmask)), sizeof(tmask)); - else - tmask = mask; - - if (strict) { - if (memcmp(&tmask, &kmask, sizeof(tmask)) != 0) - return (1); - - tmth.s6_addr32[0] &= tmask.s6_addr32[0]; - tmth.s6_addr32[1] &= tmask.s6_addr32[1]; - tmth.s6_addr32[2] &= tmask.s6_addr32[2]; - tmth.s6_addr32[3] &= tmask.s6_addr32[3]; - - kmth.s6_addr32[0] &= kmask.s6_addr32[0]; - kmth.s6_addr32[1] &= kmask.s6_addr32[1]; - kmth.s6_addr32[2] &= kmask.s6_addr32[2]; - kmth.s6_addr32[3] &= kmask.s6_addr32[3]; - - } else { - tmask.s6_addr32[0] &= kmask.s6_addr32[0]; - tmask.s6_addr32[1] &= kmask.s6_addr32[1]; - tmask.s6_addr32[2] &= kmask.s6_addr32[2]; - tmask.s6_addr32[3] &= kmask.s6_addr32[3]; - - if (memcmp(&tmask, &kmask, sizeof(tmask)) != 0) - return (1); - - tmth.s6_addr32[0] &= kmask.s6_addr32[0]; - tmth.s6_addr32[1] &= kmask.s6_addr32[1]; - tmth.s6_addr32[2] &= kmask.s6_addr32[2]; - tmth.s6_addr32[3] &= kmask.s6_addr32[3]; - - kmth.s6_addr32[0] &= kmask.s6_addr32[0]; - kmth.s6_addr32[1] &= kmask.s6_addr32[1]; - kmth.s6_addr32[2] &= kmask.s6_addr32[2]; - kmth.s6_addr32[3] &= kmask.s6_addr32[3]; - - } - - return memcmp(&tmth, &kmth, sizeof(tmth)); -} -#endif /* INET6 */ - -int -swofp_ox_cmp_ipv4_addr(struct ofp_ox_match *target, - struct ofp_ox_match *key, int strict) -{ - uint32_t tmth, tmask, kmth, kmask; - - if (OFP_OXM_GET_FIELD(target) != OFP_OXM_GET_FIELD(key)) - return (1); - - switch (OFP_OXM_GET_FIELD(target)) { - case OFP_XM_NXMT_TUNNEL_IPV4_SRC: - case OFP_XM_NXMT_TUNNEL_IPV4_DST: - case OFP_XM_T_IPV4_SRC: - case OFP_XM_T_IPV4_DST: - case OFP_XM_T_ARP_SPA: - case OFP_XM_T_ARP_TPA: - break; - default: - return (1); - } - - memcpy(&tmth, ((caddr_t)target + sizeof(*target)), sizeof(uint32_t)); - if (OFP_OXM_GET_HASMASK(target)) - memcpy(&tmask, ((caddr_t)target + sizeof(*target) + - sizeof(uint32_t)), sizeof(uint32_t)); - else - tmask = UINT32_MAX; - - memcpy(&kmth, ((caddr_t)key + sizeof(*key)), sizeof(uint32_t)); - if (OFP_OXM_GET_HASMASK(key)) - memcpy(&kmask, ((caddr_t)key + sizeof(*key) + - sizeof(uint32_t)), sizeof(uint32_t)); - else - kmask = UINT32_MAX; - - if (strict) { - if (tmask != kmask) - return (1); - } else { - if ((tmask & kmask) != kmask) - return (1); - } - - return !((tmth & kmask) == (kmth & kmask)); -} - -int -swofp_ox_cmp_vlan_vid(struct ofp_ox_match *target, - struct ofp_ox_match *key, int strict) -{ - uint16_t tmth, tmask, kmth, kmask; - - if (OFP_OXM_GET_FIELD(target) != OFP_OXM_GET_FIELD(key) || - OFP_OXM_GET_FIELD(target) != OFP_XM_T_VLAN_VID) - return (1); - - memcpy(&tmth, ((caddr_t)target + sizeof(*target)), sizeof(uint16_t)); - if (OFP_OXM_GET_HASMASK(target)) - memcpy(&tmask, ((caddr_t)target + sizeof(*target) - + sizeof(uint16_t)), sizeof(uint16_t)); - else - tmask = UINT16_MAX; - - memcpy(&kmth, ((caddr_t)key + sizeof(*key)), sizeof(uint16_t)); - if (OFP_OXM_GET_HASMASK(key)) - memcpy(&kmask, ((caddr_t)key + sizeof(*key) + - sizeof(uint16_t)), sizeof(uint16_t)); - else - kmask = UINT16_MAX; - - tmth &= htons(EVL_VLID_MASK); - tmask &= htons(EVL_VLID_MASK); - kmth &= htons(EVL_VLID_MASK); - kmask &= htons(EVL_VLID_MASK); - - if (strict) { - if (tmask != kmask) - return (1); - } else { - if ((tmask & kmask) != kmask) - return (1); - } - - return !((tmth & kmask) == (kmth & kmask)); -} - -int -swofp_ox_cmp_ether_addr(struct ofp_ox_match *target, - struct ofp_ox_match *key, int strict) -{ - uint64_t tmth, tmask, kmth, kmask; - uint64_t eth_mask = 0x0000FFFFFFFFFFFFULL; - - - if (OFP_OXM_GET_FIELD(target) != OFP_OXM_GET_FIELD(key)) - return (1); - - switch (OFP_OXM_GET_FIELD(target)) { - case OFP_XM_T_ETH_SRC: - case OFP_XM_T_ETH_DST: - case OFP_XM_T_ARP_SHA: - case OFP_XM_T_ARP_THA: - case OFP_XM_T_IPV6_ND_SLL: - case OFP_XM_T_IPV6_ND_TLL: - break; - default: - return (1); - } - - memcpy(&tmth, ((caddr_t)target + sizeof(*target)), ETHER_ADDR_LEN); - if (OFP_OXM_GET_HASMASK(target)) - memcpy(&tmask, ((caddr_t)target + sizeof(*target) + - ETHER_ADDR_LEN), ETHER_ADDR_LEN); - else - tmask = UINT64_MAX; - - memcpy(&kmth, ((caddr_t)key + sizeof(*key)), ETHER_ADDR_LEN); - if (OFP_OXM_GET_HASMASK(key)) - memcpy(&kmask, ((caddr_t)key + sizeof(*key) + - ETHER_ADDR_LEN), ETHER_ADDR_LEN); - else - kmask = UINT64_MAX; - - tmask &= eth_mask; - tmth &= eth_mask; - kmask &= eth_mask; - kmth &= eth_mask; - - if (strict) { - if (tmask != kmask) - return (1); - } else { - if ((tmask & kmask) != kmask) - return (1); - } - - return !((tmth & kmask) == (kmth & kmask)); -} - -int -swofp_validate_oxm(struct ofp_ox_match *oxm, uint16_t *err) -{ - struct ofp_oxm_class *handler; - int hasmask; - int neededlen; - - handler = swofp_lookup_oxm_handler(oxm); - if (handler == NULL || handler->oxm_match == NULL) { - *err = OFP_ERRMATCH_BAD_FIELD; - return (-1); - } - - hasmask = OFP_OXM_GET_HASMASK(oxm); - - neededlen = (hasmask) ? - (handler->oxm_len * 2) : (handler->oxm_len); - if (oxm->oxm_length != neededlen) { - *err = OFP_ERRMATCH_BAD_LEN; - return (-1); - } - - return (0); -} - -int -swofp_validate_flow_match(struct ofp_match *om, uint16_t *err) -{ - struct ofp_ox_match *oxm; - - /* - * TODO this function is missing checks for: - * - OFP_ERRMATCH_BAD_TAG; - * - OFP_ERRMATCH_BAD_VALUE; - * - OFP_ERRMATCH_BAD_MASK; - * - OFP_ERRMATCH_BAD_PREREQ; - * - OFP_ERRMATCH_DUP_FIELD; - */ - OFP_OXM_FOREACH(om, ntohs(om->om_length), oxm) { - if (swofp_validate_oxm(oxm, err)) - return (*err); - } - - return (0); -} - -int -swofp_validate_flow_instruction(struct switch_softc *sc, - struct ofp_instruction *oi, size_t total, uint16_t *etype, - uint16_t *err) -{ - struct ofp_action_header *oah; - struct ofp_instruction_actions *oia; - int ilen; - - *etype = OFP_ERRTYPE_BAD_INSTRUCTION; - - ilen = ntohs(oi->i_len); - /* Check for bigger than packet or smaller than header. */ - if (ilen > total || ilen < sizeof(*oi)) { - *err = OFP_ERRINST_BAD_LEN; - return (-1); - } - - switch (ntohs(oi->i_type)) { - case OFP_INSTRUCTION_T_GOTO_TABLE: - if (ilen != sizeof(struct ofp_instruction_goto_table)) { - *err = OFP_ERRINST_BAD_LEN; - return (-1); - } - break; - case OFP_INSTRUCTION_T_WRITE_META: - if (ilen != sizeof(struct ofp_instruction_write_metadata)) { - *err = OFP_ERRINST_BAD_LEN; - return (-1); - } - break; - case OFP_INSTRUCTION_T_METER: - if (ilen != sizeof(struct ofp_instruction_meter)) { - *err = OFP_ERRINST_BAD_LEN; - return (-1); - } - break; - - case OFP_INSTRUCTION_T_WRITE_ACTIONS: - case OFP_INSTRUCTION_T_CLEAR_ACTIONS: - case OFP_INSTRUCTION_T_APPLY_ACTIONS: - if (ilen < sizeof(*oia)) { - *err = OFP_ERRINST_BAD_LEN; - return (-1); - } - - oia = (struct ofp_instruction_actions *)oi; - - /* Validate actions before iterating over them. */ - oah = (struct ofp_action_header *) - ((uint8_t *)oia + sizeof(*oia)); - if (swofp_validate_action(sc, oah, ilen - sizeof(*oia), - err)) { - *etype = OFP_ERRTYPE_BAD_ACTION; - return (-1); - } - break; - - case OFP_INSTRUCTION_T_EXPERIMENTER: - /* FALLTHROUGH */ - default: - *err = OFP_ERRINST_UNKNOWN_INST; - return (-1); - } - - return (0); -} - -int -swofp_validate_action(struct switch_softc *sc, struct ofp_action_header *ah, - size_t ahtotal, uint16_t *err) -{ - struct ofp_action_handler *oah; - struct ofp_ox_match *oxm; - struct ofp_action_push *ap; - struct ofp_action_group *ag; - struct ofp_action_output *ao; - struct switch_port *swpo; - uint8_t *dptr; - int ahtype, ahlen, oxmlen; - - /* No actions. */ - if (ahtotal == 0) - return (0); - - /* Check if we have at least the first header. */ - if (ahtotal < sizeof(*ah)) { - *err = OFP_ERRACTION_LEN; - return (-1); - } - - parse_next_action: - ahtype = ntohs(ah->ah_type); - ahlen = ntohs(ah->ah_len); - if (ahlen < sizeof(*ah) || ahlen > ahtotal) { - *err = OFP_ERRACTION_LEN; - return (-1); - } - - switch (ahtype) { - case OFP_ACTION_OUTPUT: - if (ahlen != sizeof(struct ofp_action_output)) { - *err = OFP_ERRACTION_LEN; - return (-1); - } - - ao = (struct ofp_action_output *)ah; - switch (ntohl(ao->ao_port)) { - case OFP_PORT_ANY: - *err = OFP_ERRACTION_OUT_PORT; - return (-1); - - case OFP_PORT_ALL: - case OFP_PORT_NORMAL: - /* TODO implement port ALL and NORMAL. */ - *err = OFP_ERRACTION_OUT_PORT; - return (-1); - - case OFP_PORT_CONTROLLER: - case OFP_PORT_FLOWTABLE: - case OFP_PORT_FLOOD: - case OFP_PORT_INPUT: - case OFP_PORT_LOCAL: - break; - - default: - TAILQ_FOREACH(swpo, &sc->sc_swpo_list, - swpo_list_next) { - if (swpo->swpo_port_no == - ntohl(ao->ao_port)) - break; - } - if (swpo == NULL) { - *err = OFP_ERRACTION_OUT_PORT; - return (-1); - } - break; - } - break; - case OFP_ACTION_GROUP: - if (ahlen != sizeof(struct ofp_action_group)) { - *err = OFP_ERRACTION_LEN; - return (-1); - } - - ag = (struct ofp_action_group *)ah; - if (swofp_group_entry_lookup(sc, - ntohl(ag->ag_group_id)) == NULL) { - *err = OFP_ERRACTION_BAD_OUT_GROUP; - return (-1); - } - break; - case OFP_ACTION_SET_QUEUE: - if (ahlen != sizeof(struct ofp_action_set_queue)) { - *err = OFP_ERRACTION_LEN; - return (-1); - } - break; - case OFP_ACTION_SET_MPLS_TTL: - if (ahlen != sizeof(struct ofp_action_mpls_ttl)) { - *err = OFP_ERRACTION_LEN; - return (-1); - } - break; - case OFP_ACTION_SET_NW_TTL: - if (ahlen != sizeof(struct ofp_action_nw_ttl)) { - *err = OFP_ERRACTION_LEN; - return (-1); - } - break; - case OFP_ACTION_COPY_TTL_OUT: - case OFP_ACTION_COPY_TTL_IN: - case OFP_ACTION_DEC_MPLS_TTL: - case OFP_ACTION_POP_VLAN: - if (ahlen != sizeof(struct ofp_action_header)) { - *err = OFP_ERRACTION_LEN; - return (-1); - } - break; - case OFP_ACTION_PUSH_VLAN: - case OFP_ACTION_PUSH_MPLS: - case OFP_ACTION_PUSH_PBB: - if (ahlen != sizeof(struct ofp_action_push)) { - *err = OFP_ERRACTION_LEN; - return (-1); - } - - ap = (struct ofp_action_push *)ah; - switch (ntohs(ap->ap_type)) { - case OFP_ACTION_PUSH_VLAN: - if (ntohs(ap->ap_ethertype) != ETHERTYPE_VLAN && - ntohs(ap->ap_ethertype) != ETHERTYPE_QINQ) { - *err = OFP_ERRACTION_ARGUMENT; - return (-1); - } - break; - - case OFP_ACTION_PUSH_MPLS: - case OFP_ACTION_PUSH_PBB: - /* Not implemented yet. */ - default: - *err = OFP_ERRACTION_TYPE; - return (-1); - } - break; - case OFP_ACTION_POP_MPLS: - if (ahlen != sizeof(struct ofp_action_pop_mpls)) { - *err = OFP_ERRACTION_LEN; - return (-1); - } - break; - case OFP_ACTION_SET_FIELD: - if (ahlen < sizeof(struct ofp_action_set_field) || - ahlen != OFP_ALIGN(ahlen)) { - *err = OFP_ERRACTION_LEN; - return (-1); - } - - oxmlen = ahlen - (sizeof(struct ofp_action_set_field) - - offsetof(struct ofp_action_set_field, asf_field)); - if (oxmlen < sizeof(*oxm)) { - *err = OFP_ERRACTION_LEN; - return (-1); - } - - dptr = (uint8_t *)ah; - dptr += sizeof(struct ofp_action_set_field) - - offsetof(struct ofp_action_set_field, asf_field); - oxm = (struct ofp_ox_match *)dptr; - oxmlen -= sizeof(struct ofp_ox_match); - if (oxmlen < oxm->oxm_length) { - *err = OFP_ERRACTION_SET_LEN; - return (-1); - } - /* Remainder is padding. */ - oxmlen -= oxm->oxm_length; - if (oxmlen >= OFP_ALIGNMENT) { - *err = OFP_ERRACTION_SET_LEN; - return (-1); - } - - if (swofp_validate_oxm(oxm, err)) { - if (*err == OFP_ERRMATCH_BAD_LEN) - *err = OFP_ERRACTION_SET_LEN; - else - *err = OFP_ERRACTION_SET_TYPE; - return (-1); - } - - dptr += sizeof(struct ofp_ox_match) + oxm->oxm_length; - while (oxmlen > 0) { - if (*dptr != 0) { - *err = OFP_ERRACTION_SET_ARGUMENT; - return (-1); - } - oxmlen--; - dptr++; - } - break; - default: - /* Unknown/unsupported action. */ - *err = OFP_ERRACTION_TYPE; - return (-1); - } - - oah = swofp_lookup_action_handler(ahtype); - /* Unknown/unsupported action. */ - if (oah == NULL) { - *err = OFP_ERRACTION_TYPE; - return (-1); - } - - ahtotal -= min(ahlen, ahtotal); - if (ahtotal) { - ah = (struct ofp_action_header *)((uint8_t *)ah + ahlen); - goto parse_next_action; - } - - return (0); -} - -int -swofp_flow_filter_out_port(struct ofp_instruction_actions *oia, - uint32_t out_port) -{ - struct ofp_action_header *oah; - struct ofp_action_output *oao; - - if (oia == NULL) - return (0); - - OFP_I_ACTIONS_FOREACH((struct ofp_instruction_actions *)oia, oah) { - if (ntohs(oah->ah_type) == OFP_ACTION_OUTPUT) { - oao = (struct ofp_action_output *)oah; - if (ntohl(oao->ao_port) == out_port) - return (1); - } - } - - return (0); -} - -int -swofp_flow_filter(struct swofp_flow_entry *swfe, uint64_t cookie, - uint64_t cookie_mask, uint32_t out_port, uint32_t out_group) -{ - - if (cookie_mask != 0 && - ((swfe->swfe_cookie & cookie_mask) != (cookie & cookie_mask))) - return (0); - - if ((out_port == OFP_PORT_ANY) && (out_group == OFP_GROUP_ID_ALL)) - return (1); - - if ((out_port != OFP_PORT_ANY) && - !(swofp_flow_filter_out_port(swfe->swfe_write_actions, out_port) || - swofp_flow_filter_out_port(swfe->swfe_apply_actions, out_port))) - return (0); - - if (out_port != OFP_GROUP_ID_ALL) { - /* XXX ignore group */ - } - - return (1); -} - -int -swofp_flow_cmp_common(struct swofp_flow_entry *swfe, struct ofp_match *key, - int strict) -{ - struct ofp_match *target = swfe->swfe_match; - struct ofp_oxm_class *khandler; - struct ofp_ox_match *toxm, *koxm; - void *kmask; - int len; - /* maximam payload size is size of struct in6_addr */ - uint8_t dummy_unmask[sizeof(struct in6_addr)]; - - memset(dummy_unmask, 0, sizeof(dummy_unmask)); - - OFP_OXM_FOREACH(key, ntohs(key->om_length), koxm) { - khandler = swofp_lookup_oxm_handler(koxm); - if (khandler == NULL || khandler->oxm_match == NULL) - return (0); - - len = khandler->oxm_len; - - /* - * OpenFlow Switch Specification 1.3.5 says: - * - An all-zero-bits oxm_mask is equivalent to omitting - * the OXM TLV entirely - */ - if (strict && OFP_OXM_GET_HASMASK(koxm)) { - kmask = (void *)((caddr_t)koxm + sizeof(*koxm) + len); - if (memcmp(kmask, dummy_unmask, len) == 0) - continue; - } - - OFP_OXM_FOREACH(target, ntohs(target->om_length), toxm) { - if (khandler->oxm_cmp(toxm, koxm, strict) == 0) - break; - } - if (OFP_OXM_TERMINATED(target, ntohs(target->om_length), toxm)) - return (0); - } - - return (1); -} - -int -swofp_flow_cmp_non_strict(struct swofp_flow_entry *swfe, struct ofp_match *key) -{ - /* Every oxm matching is wildcard */ - if (key == NULL) - return (1); - - return swofp_flow_cmp_common(swfe, key, 0); -} - -int -swofp_flow_cmp_strict(struct swofp_flow_entry *swfe, struct ofp_match *key, - uint32_t priority) -{ - struct ofp_match *target = swfe->swfe_match; - struct ofp_ox_match *toxm, *koxm; - int key_matches, target_matches; - - /* - * Both target and key values are put on network byte order, - * so it's ok that those are compared without changing byte order - */ - if (swfe->swfe_priority != priority) - return (0); - - key_matches = target_matches = 0; - OFP_OXM_FOREACH(key, ntohs(key->om_length), koxm) - key_matches++; - - OFP_OXM_FOREACH(target, ntohs(target->om_length), toxm) - target_matches++; - - if (key_matches != target_matches) - return (0); - - return swofp_flow_cmp_common(swfe, key, 1); -} - -struct swofp_flow_entry * -swofp_flow_search_by_table(struct swofp_flow_table *swft, struct ofp_match *key, - uint16_t priority) -{ - struct swofp_flow_entry *swfe; - - LIST_FOREACH(swfe, &swft->swft_flow_list, swfe_next) { - if (swofp_flow_cmp_strict(swfe, key, priority)) - return (swfe); - } - - return (NULL); -} - -int -swofp_flow_has_group(struct ofp_instruction_actions *oia, uint32_t group_id) -{ - struct ofp_action_header *oah; - struct ofp_action_group *oag; - - if (oia == NULL) - return (0); - - OFP_I_ACTIONS_FOREACH((struct ofp_instruction_actions *)oia, oah) { - if (ntohs(oah->ah_type) == OFP_ACTION_GROUP) { - oag = (struct ofp_action_group *)oah; - if (ntohl(oag->ag_group_id) == group_id) - return (1); - } - } - - return (0); -} - -void -swofp_flow_delete_on_table_by_group(struct switch_softc *sc, - struct swofp_flow_table *swft, uint32_t group_id) -{ - struct swofp_flow_entry *swfe, *tswfe; - - LIST_FOREACH_SAFE(swfe, &swft->swft_flow_list, swfe_next, tswfe) { - if (swofp_flow_has_group(swfe->swfe_apply_actions, group_id) || - swofp_flow_has_group(swfe->swfe_write_actions, group_id)) { - swofp_flow_entry_delete(sc, swft, swfe, - OFP_FLOWREM_REASON_GROUP_DELETE); - } - } -} - -void -swofp_flow_delete_on_table(struct switch_softc *sc, - struct swofp_flow_table *swft, struct ofp_match *key, uint16_t priority, - uint64_t cookie, uint64_t cookie_mask, uint32_t out_port, - uint32_t out_group, int strict) -{ - struct swofp_flow_entry *swfe, *tswfe; - - LIST_FOREACH_SAFE(swfe, &swft->swft_flow_list, swfe_next, tswfe) { - if (strict && !swofp_flow_cmp_strict(swfe, key, priority)) - continue; - else if (!swofp_flow_cmp_non_strict(swfe, key)) - continue; - - if (!swofp_flow_filter(swfe, cookie, cookie_mask, - out_port, out_group)) - continue; - - swofp_flow_entry_delete(sc, swft, swfe, - OFP_FLOWREM_REASON_DELETE); - } -} - -void -swofp_ox_match_put_start(struct ofp_match *om) -{ - om->om_type = htons(OFP_MATCH_OXM); - om->om_length = htons(sizeof(*om)); -} - -/* - * Return ofp_match length include "PADDING" byte - */ -int -swofp_ox_match_put_end(struct ofp_match *om) -{ - int tsize = ntohs(om->om_length); - int padding; - - padding = OFP_ALIGN(tsize) - tsize; - if (padding) - memset((caddr_t)om + tsize, 0, padding); - - return tsize + padding; -} - -int -swofp_ox_match_put_uint32(struct ofp_match *om, uint8_t type, uint32_t val) -{ - int off = ntohs(om->om_length); - struct ofp_ox_match *oxm; - - val = htonl(val); - oxm = (struct ofp_ox_match *)((caddr_t)om + off); - oxm->oxm_class = htons(OFP_OXM_C_OPENFLOW_BASIC); - OFP_OXM_SET_FIELD(oxm, type); - oxm->oxm_length = sizeof(uint32_t); - memcpy(oxm->oxm_value, &val, sizeof(val)); - om->om_length = htons(ntohs(om->om_length) + - sizeof(*oxm) + sizeof(uint32_t)); - - return ntohs(om->om_length); -} - -int -swofp_ox_match_put_uint64(struct ofp_match *om, uint8_t type, uint64_t val) -{ - struct ofp_ox_match *oxm; - int off = ntohs(om->om_length); - - val = htobe64(val); - oxm = (struct ofp_ox_match *)((caddr_t)om + off); - oxm->oxm_class = htons(OFP_OXM_C_OPENFLOW_BASIC); - OFP_OXM_SET_FIELD(oxm, type); - oxm->oxm_length = sizeof(uint64_t); - memcpy(oxm->oxm_value, &val, sizeof(val)); - om->om_length = htons(ntohs(om->om_length) + - sizeof(*oxm) + sizeof(uint64_t)); - - return ntohs(om->om_length); -} - -int -swofp_nx_match_put(struct ofp_match *om, uint8_t type, int len, - caddr_t val) -{ - struct ofp_ox_match *oxm; - int off = ntohs(om->om_length); - - oxm = (struct ofp_ox_match *)((caddr_t)om + off); - oxm->oxm_class = htons(OFP_OXM_C_NXM_1); - OFP_OXM_SET_FIELD(oxm, type); - oxm->oxm_length = len; - memcpy((void *)oxm->oxm_value, val, len); - - om->om_length = htons(ntohs(om->om_length) + sizeof(*oxm) + len); - - return ntohs(om->om_length); -} - -int -swofp_ox_set_vlan_vid(struct switch_flow_classify *swfcl, - struct ofp_ox_match *oxm) -{ - uint16_t val; - - val = *(uint16_t *)oxm->oxm_value; - swfcl->swfcl_vlan->vlan_vid = (val & htons(EVL_VLID_MASK)); - - return (0); -} - -int -swofp_ox_set_uint8(struct switch_flow_classify *swfcl, - struct ofp_ox_match *oxm) -{ - uint8_t val; - - val = *(uint8_t *)oxm->oxm_value; - - switch (OFP_OXM_GET_FIELD(oxm)) { - case OFP_XM_T_IP_DSCP: - if (swfcl->swfcl_ipv4) - swfcl->swfcl_ipv4->ipv4_tos = ((val << 2) | - (swfcl->swfcl_ipv4->ipv4_tos & IPTOS_ECN_MASK)); - else - swfcl->swfcl_ipv6->ipv6_tclass = ((val << 2) | - (swfcl->swfcl_ipv6->ipv6_tclass & IPTOS_ECN_MASK)); - break; - case OFP_XM_T_IP_ECN: - if (swfcl->swfcl_ipv4) - swfcl->swfcl_ipv4->ipv4_tos = ((val & IPTOS_ECN_MASK) | - (swfcl->swfcl_ipv4->ipv4_tos & ~IPTOS_ECN_MASK)); - else - swfcl->swfcl_ipv6->ipv6_tclass = ( - (val & IPTOS_ECN_MASK) | - (swfcl->swfcl_ipv6->ipv6_tclass & ~IPTOS_ECN_MASK)); - break; - case OFP_XM_T_IP_PROTO: - if (swfcl->swfcl_ipv4) - swfcl->swfcl_ipv4->ipv4_proto = val; - else - swfcl->swfcl_ipv6->ipv6_nxt = val; - break; - case OFP_XM_T_ICMPV4_TYPE: - swfcl->swfcl_icmpv4->icmpv4_type = val; - break; - case OFP_XM_T_ICMPV4_CODE: - swfcl->swfcl_icmpv4->icmpv4_code = val; - break; - case OFP_XM_T_ICMPV6_TYPE: - swfcl->swfcl_icmpv6->icmpv6_type = val; - break; - case OFP_XM_T_ICMPV6_CODE: - swfcl->swfcl_icmpv6->icmpv6_code = val; - break; - } - - return (0); -} - -int -swofp_ox_set_uint16(struct switch_flow_classify *swfcl, - struct ofp_ox_match *oxm) -{ - uint16_t val; - - val = *(uint16_t *)oxm->oxm_value; - - switch (OFP_OXM_GET_FIELD(oxm)) { - case OFP_XM_T_ETH_TYPE: - swfcl->swfcl_ether->eth_type = val; - break; - case OFP_XM_T_VLAN_PCP: - swfcl->swfcl_vlan->vlan_pcp = val; - break; - case OFP_XM_T_TCP_SRC: - swfcl->swfcl_tcp->tcp_src = val; - break; - case OFP_XM_T_TCP_DST: - swfcl->swfcl_tcp->tcp_dst = val; - break; - case OFP_XM_T_UDP_SRC: - swfcl->swfcl_udp->udp_src = val; - break; - case OFP_XM_T_UDP_DST: - swfcl->swfcl_udp->udp_dst = val; - break; - case OFP_XM_T_ARP_OP: - swfcl->swfcl_arp->_arp_op = val; - } - - return (0); -} - -int -swofp_ox_set_uint32(struct switch_flow_classify *swfcl, - struct ofp_ox_match *oxm) -{ - uint32_t val; - - val = *(uint32_t *)oxm->oxm_value; - - switch (OFP_OXM_GET_FIELD(oxm)) { - case OFP_XM_T_IPV6_FLABEL: - swfcl->swfcl_ipv6->ipv6_flow_label = val; - break; - } - - return (0); -} - -int -swofp_ox_set_uint64(struct switch_flow_classify *swfcl, - struct ofp_ox_match *oxm) -{ - uint64_t val; - - val = *(uint64_t *)oxm->oxm_value; - - switch (OFP_OXM_GET_FIELD(oxm)) { - case OFP_XM_T_TUNNEL_ID: /* alias OFP_XM_NXMT_TUNNEL_ID */ - swfcl->swfcl_tunnel->tun_key = val; - break; - } - - return (0); -} - -int -swofp_ox_set_ipv6_addr(struct switch_flow_classify *swfcl, - struct ofp_ox_match *oxm) -{ - struct in6_addr val; - - memcpy(&val, oxm->oxm_value, sizeof(val)); - - switch (OFP_OXM_GET_FIELD(oxm)) { - case OFP_XM_NXMT_TUNNEL_IPV6_SRC: - swfcl->swfcl_tunnel->tun_ipv6_src = val; - break; - case OFP_XM_NXMT_TUNNEL_IPV6_DST: - swfcl->swfcl_tunnel->tun_ipv6_dst = val; - break; - case OFP_XM_T_IPV6_SRC: - swfcl->swfcl_ipv6->ipv6_src = val; - break; - case OFP_XM_T_IPV6_DST: - swfcl->swfcl_ipv6->ipv6_dst = val; - break; - case OFP_XM_T_IPV6_ND_TARGET: - swfcl->swfcl_nd6->nd6_target = val; - break; - } - - return (0); -} - -int -swofp_ox_set_ipv4_addr(struct switch_flow_classify *swfcl, - struct ofp_ox_match *oxm) -{ - uint32_t val; - - val = *(uint32_t *)oxm->oxm_value; - - switch (OFP_OXM_GET_FIELD(oxm)) { - case OFP_XM_NXMT_TUNNEL_IPV4_SRC: - swfcl->swfcl_tunnel->tun_ipv4_src = *(struct in_addr *)&val; - break; - case OFP_XM_NXMT_TUNNEL_IPV4_DST: - swfcl->swfcl_tunnel->tun_ipv4_dst = *(struct in_addr *)&val; - break; - case OFP_XM_T_IPV4_SRC: - swfcl->swfcl_ipv4->ipv4_src = val; - break; - case OFP_XM_T_IPV4_DST: - swfcl->swfcl_ipv4->ipv4_dst = val; - break; - case OFP_XM_T_ARP_SPA: - swfcl->swfcl_arp->arp_sip = val; - break; - case OFP_XM_T_ARP_TPA: - swfcl->swfcl_arp->arp_tip = val; - break; - } - - return (0); -} - -int -swofp_ox_set_ether_addr(struct switch_flow_classify *swfcl, - struct ofp_ox_match *oxm) -{ - caddr_t eth_addr; - - eth_addr = oxm->oxm_value; - - switch (OFP_OXM_GET_FIELD(oxm)) { - case OFP_XM_T_ETH_SRC: - memcpy(swfcl->swfcl_ether->eth_src, eth_addr, ETHER_ADDR_LEN); - break; - case OFP_XM_T_ETH_DST: - memcpy(swfcl->swfcl_ether->eth_dst, eth_addr, ETHER_ADDR_LEN); - break; - case OFP_XM_T_ARP_SHA: - memcpy(swfcl->swfcl_arp->arp_sha, eth_addr, ETHER_ADDR_LEN); - break; - case OFP_XM_T_ARP_THA: - memcpy(swfcl->swfcl_arp->arp_tha, eth_addr, ETHER_ADDR_LEN); - break; - case OFP_XM_T_IPV6_ND_TLL: - case OFP_XM_T_IPV6_ND_SLL: - memcpy(swfcl->swfcl_nd6->nd6_lladdr, eth_addr, ETHER_ADDR_LEN); - break; - } - - return (0); -} - -#ifdef INET6 -int -swofp_ox_match_ipv6_addr(struct switch_flow_classify *swfcl, - struct ofp_ox_match *oxm) -{ - struct in6_addr in, mth, mask = in6mask128; - - switch (OFP_OXM_GET_FIELD(oxm)) { - case OFP_XM_NXMT_TUNNEL_IPV6_SRC: - case OFP_XM_NXMT_TUNNEL_IPV6_DST: - if (swfcl->swfcl_tunnel == NULL) - return (1); - break; - case OFP_XM_T_IPV6_SRC: - case OFP_XM_T_IPV6_DST: - if (swfcl->swfcl_ipv6 == NULL) - return (1); - break; - case OFP_XM_T_IPV6_ND_TARGET: - if (swfcl->swfcl_nd6 == NULL) - return (1); - break; - default: - return (1); - } - - switch (OFP_OXM_GET_FIELD(oxm)) { - case OFP_XM_NXMT_TUNNEL_IPV6_SRC: - in = swfcl->swfcl_tunnel->tun_ipv6_src; - break; - case OFP_XM_NXMT_TUNNEL_IPV6_DST: - in = swfcl->swfcl_tunnel->tun_ipv6_dst; - break; - case OFP_XM_T_IPV6_SRC: - in = swfcl->swfcl_ipv6->ipv6_src; - break; - case OFP_XM_T_IPV6_DST: - in = swfcl->swfcl_ipv6->ipv6_dst; - break; - case OFP_XM_T_IPV6_ND_TARGET: - in = swfcl->swfcl_nd6->nd6_target; - break; - } - - memcpy(&mth, oxm->oxm_value, sizeof(mth)); - - if (OFP_OXM_GET_HASMASK(oxm)) { - memcpy(&mask, oxm->oxm_value + sizeof(mth), - sizeof(mask)); - - in.s6_addr32[0] &= mask.s6_addr32[0]; - in.s6_addr32[1] &= mask.s6_addr32[1]; - in.s6_addr32[2] &= mask.s6_addr32[2]; - in.s6_addr32[3] &= mask.s6_addr32[3]; - - mth.s6_addr32[0] &= mask.s6_addr32[0]; - mth.s6_addr32[1] &= mask.s6_addr32[1]; - mth.s6_addr32[2] &= mask.s6_addr32[2]; - mth.s6_addr32[3] &= mask.s6_addr32[3]; - } - - return memcmp(&in, &mth, sizeof(in)); -} -#endif /* INET6 */ - -int -swofp_ox_match_ipv4_addr(struct switch_flow_classify *swfcl, - struct ofp_ox_match *oxm) -{ - uint32_t in, mth, mask; - - switch (OFP_OXM_GET_FIELD(oxm)) { - case OFP_XM_NXMT_TUNNEL_IPV4_SRC: - case OFP_XM_NXMT_TUNNEL_IPV4_DST: - if (swfcl->swfcl_tunnel == NULL) - return (1); - break; - case OFP_XM_T_IPV4_SRC: - case OFP_XM_T_IPV4_DST: - if (swfcl->swfcl_ipv4 == NULL) - return (1); - break; - case OFP_XM_T_ARP_SPA: - case OFP_XM_T_ARP_TPA: - if (swfcl->swfcl_arp == NULL) - return (1); - break; - default: - return (1); - } - - switch (OFP_OXM_GET_FIELD(oxm)) { - case OFP_XM_NXMT_TUNNEL_IPV4_SRC: - in = swfcl->swfcl_tunnel->tun_ipv4_src.s_addr; - break; - case OFP_XM_NXMT_TUNNEL_IPV4_DST: - in = swfcl->swfcl_tunnel->tun_ipv4_dst.s_addr; - break; - case OFP_XM_T_IPV4_SRC: - in = swfcl->swfcl_ipv4->ipv4_src; - break; - case OFP_XM_T_IPV4_DST: - in = swfcl->swfcl_ipv4->ipv4_dst; - break; - case OFP_XM_T_ARP_SPA: - in = swfcl->swfcl_arp->arp_sip; - break; - case OFP_XM_T_ARP_TPA: - in = swfcl->swfcl_arp->arp_tip; - break; - } - - memcpy(&mth, oxm->oxm_value, sizeof(uint32_t)); - - if (OFP_OXM_GET_HASMASK(oxm)) - memcpy(&mask, oxm->oxm_value + sizeof(uint32_t), - sizeof(uint32_t)); - else - mask = UINT32_MAX; - - return !((in & mask) == (mth & mask)); -} - -int -swofp_ox_match_vlan_vid(struct switch_flow_classify *swfcl, - struct ofp_ox_match *oxm) -{ - uint16_t in, mth, mask = 0; - - if (swfcl->swfcl_vlan == NULL) - return (1); - - in = swfcl->swfcl_vlan->vlan_vid; - memcpy(&mth, oxm->oxm_value, sizeof(uint16_t)); - - if (OFP_OXM_GET_HASMASK(oxm)) - memcpy(&mask, oxm->oxm_value + sizeof(uint16_t), - sizeof(uint16_t)); - else - mask = UINT16_MAX; - - /* - * OpenFlow Switch Specification ver 1.3.5 says if oxm value - * is OFP_XM_VID_NONE, matches only packets without a VLAN tag - */ - if (mth == htons(OFP_XM_VID_NONE)) - return (1); - - /* - * OpenFlow Switch Specification ver 1.3.5 says if oxm value and mask - * is OFP_XM_VID_PRESENT, matches only packets with a VLAN tag - * regardless of its value. - */ - if (ntohs(mth) == OFP_XM_VID_PRESENT && - ntohs(mask) == OFP_XM_VID_PRESENT) - return (0); - - in &= htons(EVL_VLID_MASK); - mth &= htons(EVL_VLID_MASK); - - return !((in & mask) == (mth & mask)); -} - -int -swofp_ox_match_uint8(struct switch_flow_classify *swfcl, - struct ofp_ox_match *oxm) -{ - uint8_t in, mth; - - switch (OFP_OXM_GET_FIELD(oxm)) { - case OFP_XM_T_VLAN_PCP: - if (swfcl->swfcl_vlan == NULL) - return (1); - break; - case OFP_XM_T_IP_DSCP: - case OFP_XM_T_IP_ECN: - case OFP_XM_T_IP_PROTO: - if ((swfcl->swfcl_ipv4 == NULL && - swfcl->swfcl_ipv6 == NULL)) - return (1); - break; - case OFP_XM_T_ICMPV4_CODE: - case OFP_XM_T_ICMPV4_TYPE: - if (swfcl->swfcl_icmpv4 == NULL) - return (1); - break; - case OFP_XM_T_ICMPV6_CODE: - case OFP_XM_T_ICMPV6_TYPE: - if (swfcl->swfcl_icmpv6 == NULL) - return (1); - break; - default: - return (1); - } - - switch (OFP_OXM_GET_FIELD(oxm)) { - case OFP_XM_T_VLAN_PCP: - in = swfcl->swfcl_vlan->vlan_pcp; - break; - case OFP_XM_T_IP_DSCP: - if (swfcl->swfcl_ipv4) - in = swfcl->swfcl_ipv4->ipv4_tos >> 2; - else - in = swfcl->swfcl_ipv6->ipv6_tclass >> 2; - break; - case OFP_XM_T_IP_ECN: - if (swfcl->swfcl_ipv4) - in = (swfcl->swfcl_ipv4->ipv4_tos) & IPTOS_ECN_MASK; - else - in = (swfcl->swfcl_ipv6->ipv6_tclass) & IPTOS_ECN_MASK; - break; - case OFP_XM_T_IP_PROTO: - if (swfcl->swfcl_ipv4) - in = swfcl->swfcl_ipv4->ipv4_proto; - else - in = swfcl->swfcl_ipv6->ipv6_nxt; - break; - case OFP_XM_T_ICMPV4_CODE: - in = swfcl->swfcl_icmpv4->icmpv4_code; - break; - case OFP_XM_T_ICMPV4_TYPE: - in = swfcl->swfcl_icmpv4->icmpv4_type; - break; - case OFP_XM_T_ICMPV6_CODE: - in = swfcl->swfcl_icmpv6->icmpv6_code; - break; - case OFP_XM_T_ICMPV6_TYPE: - in = swfcl->swfcl_icmpv6->icmpv6_type; - break; - } - - memcpy(&mth, oxm->oxm_value, sizeof(uint8_t)); - - return !(in == mth); - -} - -int -swofp_ox_match_uint16(struct switch_flow_classify *swfcl, - struct ofp_ox_match *oxm) -{ - uint16_t in, mth; - - switch (OFP_OXM_GET_FIELD(oxm)) { - case OFP_XM_T_ETH_TYPE: - if (swfcl->swfcl_ether == NULL) - return (1); - break; - case OFP_XM_T_TCP_SRC: - case OFP_XM_T_TCP_DST: - if (swfcl->swfcl_tcp == NULL) - return (1); - break; - case OFP_XM_T_UDP_SRC: - case OFP_XM_T_UDP_DST: - if (swfcl->swfcl_udp == NULL) - return (1); - break; - case OFP_XM_T_ARP_OP: - if (swfcl->swfcl_arp == NULL) - return (1); - break; - default: - return (1); - } - - switch (OFP_OXM_GET_FIELD(oxm)) { - case OFP_XM_T_ETH_TYPE: - in = swfcl->swfcl_ether->eth_type; - break; - case OFP_XM_T_TCP_SRC: - in = swfcl->swfcl_tcp->tcp_src; - break; - case OFP_XM_T_TCP_DST: - in = swfcl->swfcl_tcp->tcp_dst; - break; - case OFP_XM_T_UDP_SRC: - in = swfcl->swfcl_udp->udp_src; - break; - case OFP_XM_T_UDP_DST: - in = swfcl->swfcl_udp->udp_dst; - break; - case OFP_XM_T_ARP_OP: - in = swfcl->swfcl_arp->_arp_op; - break; - } - - memcpy(&mth, oxm->oxm_value, sizeof(uint16_t)); - - return !(in == mth); -} - -int -swofp_ox_match_uint32(struct switch_flow_classify *swfcl, - struct ofp_ox_match *oxm) -{ - uint32_t in, mth, mask, nomask = UINT32_MAX; - - switch (OFP_OXM_GET_FIELD(oxm)) { - case OFP_XM_T_IN_PORT: - /* in_port field is always exist in swfcl */ - break; - case OFP_XM_T_IPV6_FLABEL: - if (swfcl->swfcl_ipv6 == NULL) - return (1); - break; - default: - return (1); - } - - switch (OFP_OXM_GET_FIELD(oxm)) { - case OFP_XM_T_IN_PORT: - /* - * in_port isn't network byte order because - * it's pipeline match field. - */ - in = htonl(swfcl->swfcl_in_port); - break; - case OFP_XM_T_IPV6_FLABEL: - in = swfcl->swfcl_ipv6->ipv6_flow_label; - nomask &= IPV6_FLOWLABEL_MASK; - break; - } - - memcpy(&mth, oxm->oxm_value, sizeof(uint32_t)); - - if (OFP_OXM_GET_HASMASK(oxm)) - memcpy(&mask, oxm->oxm_value + sizeof(uint32_t), - sizeof(uint32_t)); - else - mask = nomask; - - return !((in & mask) == (mth & mask)); -} - -int -swofp_ox_match_uint64(struct switch_flow_classify *swfcl, - struct ofp_ox_match *oxm) -{ - uint64_t in, mth, mask; - - switch (OFP_OXM_GET_FIELD(oxm)) { - case OFP_XM_T_META: - break; - case OFP_XM_T_TUNNEL_ID: - if (swfcl->swfcl_tunnel == NULL) - return (1); - break; - default: - return (1); - } - - switch (OFP_OXM_GET_FIELD(oxm)) { - case OFP_XM_T_META: - in = swfcl->swfcl_metadata; - break; - case OFP_XM_T_TUNNEL_ID: - in = swfcl->swfcl_tunnel->tun_key; - break; - } - - memcpy(&mth, oxm->oxm_value, sizeof(uint64_t)); - - if (OFP_OXM_GET_HASMASK(oxm)) - memcpy(&mask, oxm->oxm_value + sizeof(uint64_t), - sizeof(uint64_t)); - else - mask = UINT64_MAX; - - return !((in & mask) == (mth & mask)); -} - -int -swofp_ox_match_ether_addr(struct switch_flow_classify *swfcl, - struct ofp_ox_match *oxm) -{ - uint64_t eth_mask = 0x0000FFFFFFFFFFFFULL; - uint64_t in, mth, mask; - - switch (OFP_OXM_GET_FIELD(oxm)) { - case OFP_XM_T_ETH_SRC: - case OFP_XM_T_ETH_DST: - if (swfcl->swfcl_ether == NULL) - return (1); - break; - case OFP_XM_T_ARP_SHA: - case OFP_XM_T_ARP_THA: - if (swfcl->swfcl_arp == NULL) - return (1); - break; - case OFP_XM_T_IPV6_ND_SLL: - case OFP_XM_T_IPV6_ND_TLL: - if (swfcl->swfcl_nd6 == NULL) - return (1); - break; - default: - return (1); - } - - switch (OFP_OXM_GET_FIELD(oxm)) { - case OFP_XM_T_ETH_SRC: - in = *(uint64_t *)(swfcl->swfcl_ether->eth_src); - break; - case OFP_XM_T_ETH_DST: - in = *(uint64_t *)(swfcl->swfcl_ether->eth_dst); - break; - case OFP_XM_T_ARP_SHA: - in = *(uint64_t *)(swfcl->swfcl_arp->arp_sha); - break; - case OFP_XM_T_ARP_THA: - in = *(uint64_t *)(swfcl->swfcl_arp->arp_tha); - break; - case OFP_XM_T_IPV6_ND_SLL: - case OFP_XM_T_IPV6_ND_TLL: - in = *(uint64_t *)(swfcl->swfcl_nd6->nd6_lladdr); - break; - } - - memcpy(&mth, oxm->oxm_value, ETHER_ADDR_LEN); - if (OFP_OXM_GET_HASMASK(oxm)) - memcpy(&mask, oxm->oxm_value + ETHER_ADDR_LEN, - ETHER_ADDR_LEN); - else - mask = UINT64_MAX; - - return !((in & mask & eth_mask) == (mth & mask & eth_mask)); -} - -int -swofp_flow_match_by_swfcl(struct ofp_match *om, - struct switch_flow_classify *swfcl) -{ - struct ofp_oxm_class *oxm_handler; - struct ofp_ox_match *oxm; - - OFP_OXM_FOREACH(om, ntohs(om->om_length), oxm) { - oxm_handler = swofp_lookup_oxm_handler(oxm); - if ((oxm_handler == NULL) || - (oxm_handler->oxm_match == NULL)) - continue; - - if (oxm_handler->oxm_match(swfcl, oxm)) - return (1); - } - - return (0); -} - -/* TODO: Optimization */ -struct swofp_flow_entry * -swofp_flow_lookup(struct swofp_flow_table *swft, - struct switch_flow_classify *swfcl) -{ - struct swofp_flow_entry *swfe, *interim = NULL; - - LIST_FOREACH(swfe, &swft->swft_flow_list, swfe_next) { - if (swofp_flow_match_by_swfcl(swfe->swfe_match, swfcl) != 0) - continue; - - if (interim == NULL || - (interim->swfe_priority < swfe->swfe_priority)) - interim = swfe; - } - - swft->swft_lookup_count++; - if (interim) - swft->swft_matched_count++; - - return interim; -} - -/* - * OpenFlow protocol push/pop VLAN - */ - -/* Expand 802.1Q VLAN header from M_VLANTAG mtag if it is exist. */ -struct mbuf * -swofp_expand_8021q_tag(struct mbuf *m) -{ - if ((m->m_flags & M_VLANTAG) == 0) - return (m); - - /* H/W tagging supports only 802.1Q */ - return (vlan_inject(m, ETHERTYPE_VLAN, - EVL_VLANOFTAG(m->m_pkthdr.ether_vtag) | - EVL_PRIOFTAG(m->m_pkthdr.ether_vtag))); -} - -struct mbuf * -swofp_action_pop_vlan(struct switch_softc *sc, struct mbuf *m, - struct swofp_pipeline_desc *swpld, struct ofp_action_header *oah) -{ - struct switch_flow_classify *swfcl = swpld->swpld_swfcl; - struct ether_vlan_header *evl; - struct ether_header eh; - - /* no vlan tag existing */ - if (swfcl->swfcl_vlan == NULL) { - m_freem(m); - return (NULL); - } - - if ((m->m_flags & M_VLANTAG)) { - m->m_flags &= ~M_VLANTAG; - return (m); - } - - if (m->m_len < sizeof(*evl) && - (m = m_pullup(m, sizeof(*evl))) == NULL) - return (NULL); - evl = mtod(m, struct ether_vlan_header *); - - if ((ntohs(evl->evl_encap_proto) != ETHERTYPE_VLAN) && - (ntohs(evl->evl_encap_proto) != ETHERTYPE_QINQ)) { - m_freem(m); - return (NULL); - } - - m_copydata(m, 0, ETHER_HDR_LEN, &eh); - eh.ether_type = evl->evl_proto; - - m_adj(m, sizeof(*evl)); - M_PREPEND(m, sizeof(eh), M_DONTWAIT); - if (m == NULL) - return (NULL); - m_copyback(m, 0, sizeof(eh), &eh, M_NOWAIT); - - /* - * Update classify for vlan - */ - if (m->m_len < sizeof(*evl) && - (m = m_pullup(m, sizeof(*evl))) == NULL) - return (NULL); - evl = mtod(m, struct ether_vlan_header *); - - if (ntohs(evl->evl_encap_proto) == ETHERTYPE_VLAN) { - swfcl->swfcl_vlan->vlan_tpid = htons(ETHERTYPE_VLAN); - swfcl->swfcl_vlan->vlan_vid = - (evl->evl_tag & htons(EVL_VLID_MASK)); - swfcl->swfcl_vlan->vlan_pcp = - EVL_PRIOFTAG(ntohs(evl->evl_tag)); - } else { - pool_put(&swfcl_pool, swfcl->swfcl_vlan); - swfcl->swfcl_vlan = NULL; - } - - return (m); -} - -struct mbuf * -swofp_action_push_vlan(struct switch_softc *sc, struct mbuf *m, - struct swofp_pipeline_desc *swpld, struct ofp_action_header *oah) -{ - struct switch_flow_classify *swfcl = swpld->swpld_swfcl; - struct ofp_action_push *oap; - struct ether_header *eh; - struct ether_vlan_header evh; - - /* - * Expands 802.1Q VLAN header from M_VLANTAG because switch(4) doesn't - * use H/W tagging on port currently. - */ - m = swofp_expand_8021q_tag(m); - if (m == NULL) - return (NULL); - - oap = (struct ofp_action_push *)oah; - - if ((m->m_len < sizeof(*eh)) && - ((m = m_pullup(m, sizeof(*eh))) == NULL)) { - return (NULL); - } - eh = mtod(m, struct ether_header *); - - switch (ntohs(oap->ap_ethertype)) { - case ETHERTYPE_VLAN: - if ((ntohs(eh->ether_type) == ETHERTYPE_VLAN) || - (ntohs(eh->ether_type) == ETHERTYPE_QINQ)) { - m_freem(m); - return (NULL); - } - break; - case ETHERTYPE_QINQ: - if (ntohs(eh->ether_type) != ETHERTYPE_VLAN) { - m_freem(m); - return (NULL); - } - break; - default: - m_freem(m); - return (NULL); - } - - if (swfcl->swfcl_vlan == NULL) { - swfcl->swfcl_vlan = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO); - if (swfcl->swfcl_vlan == NULL) { - m_freem(m); - return (NULL); - } - /* puts default vlan */ - swfcl->swfcl_vlan->vlan_vid = htons(1); - } - - m_copydata(m, 0, ETHER_HDR_LEN, &evh); - evh.evl_proto = evh.evl_encap_proto; - evh.evl_encap_proto = oap->ap_ethertype; - evh.evl_tag = (swfcl->swfcl_vlan->vlan_vid | - htons(swfcl->swfcl_vlan->vlan_pcp << EVL_PRIO_BITS)); - - m_adj(m, ETHER_HDR_LEN); - M_PREPEND(m, sizeof(evh), M_DONTWAIT); - if (m == NULL) - return (NULL); - - m_copyback(m, 0, sizeof(evh), &evh, M_NOWAIT); - - /* - * Update VLAN classification - */ - swfcl->swfcl_vlan->vlan_tpid = oap->ap_ethertype; - swfcl->swfcl_vlan->vlan_vid = evh.evl_tag & htons(EVL_VLID_MASK); - swfcl->swfcl_vlan->vlan_pcp = EVL_PRIOFTAG(ntohs(evh.evl_tag)); - - return (m); -} - - -/* - * OpenFlow protocol packet in - */ -int -swofp_action_output_controller(struct switch_softc *sc, struct mbuf *m0, - struct swofp_pipeline_desc *swpld , uint16_t frame_max_len, uint8_t reason) -{ - struct swofp_ofs *swofs = sc->sc_ofs; - struct switch_flow_classify *swfcl = swpld->swpld_swfcl; - struct ofp_packet_in *pin; - struct ofp_match *om; - struct ofp_ox_match *oxm; - struct mbuf *m; - caddr_t tail; - int match_len; - - if (reason != OFP_PKTIN_REASON_ACTION) - frame_max_len = swofs->swofs_switch_config.cfg_miss_send_len; - /* - * ofp_match in packet_in has only OFP_XM_T_INPORT, OFP_MX_T_META, - * OFP_XM_NXMT_TUNNEL_IPV{4|6}_{SRC|DST} and OFP_MX_T_TUNNEL_ID that - * if exist, so ofp_match length is determined here. - */ - match_len = ( - sizeof(*om) + /* struct ofp_match */ - (sizeof(*oxm) + sizeof(uint32_t)) + /* OFP_MX_T_IMPORT */ - (sizeof(*oxm) + sizeof(uint64_t)) /* OFP_MX_T_META */ - ); - - if (swfcl->swfcl_tunnel) { - /* OFP_MX_T_TUNNEL_ID */ - match_len += (sizeof(*oxm) + sizeof(uint64_t)); - - /* OFP_XM_NXMT_TUNNEL_IPV{4|6}_{SRC|DST} */ - if (swfcl->swfcl_tunnel->tun_af == AF_INET) - match_len += (sizeof(*oxm) + sizeof(uint32_t)) * 2; - else if (swfcl->swfcl_tunnel->tun_af == AF_INET6) - match_len += (sizeof(*oxm) + - sizeof(struct in6_addr)) * 2; - } - - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) { - m_freem(m0); - return (ENOBUFS); - } - if ((sizeof(*pin) + match_len) >= MHLEN) { - MCLGET(m, M_DONTWAIT); - if ((m->m_flags & M_EXT) == 0) { - m_freem(m); - m_freem(m0); - return (ENOBUFS); - } - } - - pin = mtod(m, struct ofp_packet_in *); - memset(pin, 0, sizeof(*pin)); - - pin->pin_oh.oh_version = OFP_V_1_3; - pin->pin_oh.oh_type = OFP_T_PACKET_IN; - pin->pin_oh.oh_xid = htonl(swofs->swofs_xidnxt++); - - pin->pin_buffer_id = htonl(OFP_PKTOUT_NO_BUFFER); - pin->pin_table_id = swpld->swpld_table_id; - pin->pin_cookie = swpld->swpld_cookie; - pin->pin_reason = reason; - - if (frame_max_len) { - /* - * The switch should only truncate packets if it implements - * buffering or the controller might end up sending PACKET_OUT - * responses with truncated packets that will eventually end - * up on the network. - */ - if (frame_max_len < m0->m_pkthdr.len) { - m_freem(m); - m_freem(m0); - return (EMSGSIZE); - } - pin->pin_total_len = htons(m0->m_pkthdr.len); - } - - /* - * It's ensured continuous memory space between ofp_mach space - */ - om = &pin->pin_match; - swofp_ox_match_put_start(om); - swofp_ox_match_put_uint32(om, OFP_XM_T_IN_PORT, swfcl->swfcl_in_port); - swofp_ox_match_put_uint64(om, OFP_XM_T_META, swpld->swpld_metadata); - if (swfcl->swfcl_tunnel) { - swofp_ox_match_put_uint64(om, OFP_XM_T_TUNNEL_ID, - be64toh(swfcl->swfcl_tunnel->tun_key)); - - if (swfcl->swfcl_tunnel->tun_af == AF_INET) { - swofp_nx_match_put(om, OFP_XM_NXMT_TUNNEL_IPV4_SRC, - sizeof(uint32_t), - (caddr_t)&swfcl->swfcl_tunnel->tun_ipv4_src); - swofp_nx_match_put(om, OFP_XM_NXMT_TUNNEL_IPV4_DST, - sizeof(uint32_t), - (caddr_t)&swfcl->swfcl_tunnel->tun_ipv4_dst); - } else if (swfcl->swfcl_tunnel->tun_af == AF_INET6) { - swofp_nx_match_put(om, OFP_XM_NXMT_TUNNEL_IPV6_SRC, - sizeof(struct in6_addr), - (caddr_t)&swfcl->swfcl_tunnel->tun_ipv6_src); - swofp_nx_match_put(om, OFP_XM_NXMT_TUNNEL_IPV6_DST, - sizeof(struct in6_addr), - (caddr_t)&swfcl->swfcl_tunnel->tun_ipv6_dst); - } - } - match_len = swofp_ox_match_put_end(om); /* match_len include padding */ - - /* - * Adjust alignment for Ethernet header - */ - tail = (caddr_t)pin + - offsetof(struct ofp_packet_in, pin_match) + match_len; - memset(tail, 0, ETHER_ALIGN); - - m->m_len = m->m_pkthdr.len = - offsetof(struct ofp_packet_in, pin_match) + match_len + ETHER_ALIGN; - - pin->pin_oh.oh_length = - htons(m->m_pkthdr.len + ntohs(pin->pin_total_len)); - - if (frame_max_len) { - /* m_cat() doesn't update the m_pkthdr.len */ - m_cat(m, m0); - m->m_pkthdr.len += ntohs(pin->pin_total_len); - } - - (void)swofp_output(sc, m); - - return (0); -} - -struct mbuf * -swofp_action_output(struct switch_softc *sc, struct mbuf *m, - struct swofp_pipeline_desc *swpld, struct ofp_action_header *oah) -{ - struct ofp_action_output *oao; - struct switch_port *swpo; - struct mbuf *mc; - uint32_t protected = 0; - - m->m_pkthdr.csum_flags = 0; - - if ((m = swofp_apply_set_field(m, swpld)) == NULL) - return (NULL); - - oao = (struct ofp_action_output *)oah; - - switch (ntohl(oao->ao_port)) { - case OFP_PORT_CONTROLLER: - case OFP_PORT_FLOWTABLE: - if ((mc = m_dup_pkt(m, ETHER_ALIGN, M_NOWAIT)) == NULL) { - m_freem(m); - return (NULL); - } - } - - TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) { - if (swpo->swpo_port_no == - swpld->swpld_swfcl->swfcl_in_port) { - protected = swpo->swpo_protected; - break; - } - } - - switch (ntohl(oao->ao_port)) { - case OFP_PORT_CONTROLLER: - swofp_action_output_controller(sc, mc, swpld, - ntohs(oao->ao_max_len), swpld->swpld_tablemiss ? - OFP_PKTIN_REASON_NO_MATCH : OFP_PKTIN_REASON_ACTION); - break; - case OFP_PORT_FLOWTABLE: - swofp_forward_ofs(sc, swpld->swpld_swfcl, mc); - break; - case OFP_PORT_FLOOD: - TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) { - if (swpo->swpo_port_no != - swpld->swpld_swfcl->swfcl_in_port && - (protected & swpo->swpo_protected) == 0) - TAILQ_INSERT_HEAD(&swpld->swpld_fwdp_q, swpo, - swpo_fwdp_next); - } - break; - case OFP_PORT_INPUT: - TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) { - if (swpo->swpo_port_no == - swpld->swpld_swfcl->swfcl_in_port) { - TAILQ_INSERT_HEAD(&swpld->swpld_fwdp_q, swpo, - swpo_fwdp_next); - break; - } - } - break; - case OFP_PORT_NORMAL: - case OFP_PORT_ALL: - case OFP_PORT_ANY: - /* no support yet */ - break; - case OFP_PORT_LOCAL: - TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) { - if ((swpo->swpo_flags & IFBIF_LOCAL) && - (protected & swpo->swpo_protected) == 0) { - TAILQ_INSERT_HEAD(&swpld->swpld_fwdp_q, swpo, - swpo_fwdp_next); - break; - } - } - break; - default: - TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) { - if (swpo->swpo_port_no == ntohl(oao->ao_port) && - (protected & swpo->swpo_protected) == 0) - TAILQ_INSERT_HEAD(&swpld->swpld_fwdp_q, swpo, - swpo_fwdp_next); - } - break; - } - - if (!TAILQ_EMPTY(&swpld->swpld_fwdp_q)) { - if ((mc = m_dup_pkt(m, ETHER_ALIGN, M_NOWAIT)) == NULL) { - m_freem(m); - return (NULL); - } - switch_port_egress(sc, &swpld->swpld_fwdp_q, mc); - TAILQ_INIT(&swpld->swpld_fwdp_q); - } - - return (m); -} - - -struct mbuf * -swofp_action_group_all(struct switch_softc *sc, struct mbuf *m, - struct swofp_pipeline_desc *swpld, struct swofp_group_entry *swge) -{ - struct ofp_bucket *bucket; - struct ofp_action_header *ah; - int actions_len; - struct swofp_pipeline_desc *clean_swpld = NULL; - struct switch_flow_classify swfcl; - struct mbuf *n; - - /* Don't do anything if we don't have buckets. */ - if (swge->swge_buckets == NULL) - return (m); - - OFP_BUCKETS_FOREACH(swge->swge_buckets, - swge->swge_buckets_len, bucket) { - if (switch_swfcl_dup(swpld->swpld_swfcl, &swfcl) != 0) - goto failed; - - clean_swpld = swofp_pipeline_desc_create(&swfcl); - if (clean_swpld == NULL) - goto failed; - - if ((n = m_dup_pkt(m, ETHER_ALIGN, M_NOWAIT)) == NULL) - goto failed; - - actions_len = (ntohs(bucket->b_len) - - (offsetof(struct ofp_bucket, b_actions))); - - OFP_ACTION_FOREACH(bucket->b_actions, actions_len, ah) { - n = swofp_execute_action(sc, n, clean_swpld, ah); - if (n == NULL) - goto failed; - } - - m_freem(n); - swofp_pipeline_desc_destroy(clean_swpld); - clean_swpld = NULL; - switch_swfcl_free(&swfcl); - } - - return (m); - - failed: - m_freem(m); - if (clean_swpld) - swofp_pipeline_desc_destroy(clean_swpld); - return (NULL); -} - -struct mbuf * -swofp_action_group(struct switch_softc *sc, struct mbuf *m, - struct swofp_pipeline_desc *swpld, struct ofp_action_header *oah) -{ - struct ofp_action_group *oag; - struct swofp_group_entry *swge; - - oag = (struct ofp_action_group *)oah; - - swge = swofp_group_entry_lookup(sc, ntohl(oag->ag_group_id)); - if (swge == NULL) { - m_freem(m); - return (NULL); - } - - swge->swge_packet_count++; - swge->swge_byte_count += m->m_pkthdr.len; - - switch (swge->swge_type) { - case OFP_GROUP_T_ALL: - return swofp_action_group_all(sc, m, swpld, swge); - case OFP_GROUP_T_INDIRECT: - case OFP_GROUP_T_FAST_FAILOVER: - case OFP_GROUP_T_SELECT: - m_freem(m); - return (NULL); - } - - return (m); -} - -struct mbuf * -swofp_apply_set_field_udp(struct mbuf *m, int off, - struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl) -{ - struct udphdr *uh; - - if (m->m_len < (off + sizeof(*uh)) && - (m = m_pullup(m, off + sizeof(*uh))) == NULL) - return NULL; - - uh = (struct udphdr *)((m)->m_data + off); - - if (pre_swfcl->swfcl_udp) { - uh->uh_sport = pre_swfcl->swfcl_udp->udp_src; - uh->uh_dport = pre_swfcl->swfcl_udp->udp_dst; - memcpy(swfcl->swfcl_udp, pre_swfcl->swfcl_udp, - sizeof(*swfcl->swfcl_udp)); - } - - return (m); -} - -struct mbuf * -swofp_apply_set_field_tcp(struct mbuf *m, int off, - struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl) -{ - struct tcphdr *th; - - if (m->m_len < (off + sizeof(*th)) && - (m = m_pullup(m, off + sizeof(*th))) == NULL) - return NULL; - - th = (struct tcphdr *)((m)->m_data + off); - - if (pre_swfcl->swfcl_tcp) { - th->th_sport = pre_swfcl->swfcl_tcp->tcp_src; - th->th_dport = pre_swfcl->swfcl_tcp->tcp_dst; - - memcpy(swfcl->swfcl_tcp, pre_swfcl->swfcl_tcp, - sizeof(*swfcl->swfcl_tcp)); - } - - return (m); -} - -#ifdef INET6 -struct mbuf * -swofp_apply_set_field_nd6(struct mbuf *m, int off, - struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl) -{ - struct icmp6_hdr *icmp6; - struct nd_neighbor_advert *nd_na; - struct nd_neighbor_solicit *nd_ns; - union nd_opts ndopts; - int icmp6len = m->m_pkthdr.len - off; - int lladdrlen; - uint8_t *lladdr; - - if (pre_swfcl->swfcl_nd6 == NULL) - return (m); - - IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6)); - if (icmp6 == NULL) - goto failed; - - switch (icmp6->icmp6_type) { - case ND_NEIGHBOR_ADVERT: - if (icmp6len < sizeof(struct nd_neighbor_advert)) - goto failed; - break; - case ND_NEIGHBOR_SOLICIT: - if (icmp6len < sizeof(struct nd_neighbor_solicit)) - goto failed; - break; - } - - switch (icmp6->icmp6_type) { - case ND_NEIGHBOR_ADVERT: - IP6_EXTHDR_GET(nd_na, struct nd_neighbor_advert *, m, - off, icmp6len); - if (nd_na == NULL) - goto failed; - - nd_na->nd_na_target = pre_swfcl->swfcl_nd6->nd6_target; - icmp6len -= sizeof(*nd_na); - nd6_option_init(nd_na + 1, icmp6len, &ndopts); - if (nd6_options(&ndopts) < 0) - goto failed; - - if (!ndopts.nd_opts_tgt_lladdr) - goto failed; - - lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1); - lladdrlen = (ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3) - 2; - - /* switch(4) only supports Ethernet interfaces */ - if (lladdrlen != ETHER_ADDR_LEN) - goto failed; - - memcpy(lladdr, pre_swfcl->swfcl_nd6->nd6_lladdr, - ETHER_ADDR_LEN); - break; - case ND_NEIGHBOR_SOLICIT: - IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m, - off, icmp6len); - if (nd_ns == NULL) - goto failed; - - nd_ns->nd_ns_target = pre_swfcl->swfcl_nd6->nd6_target; - icmp6len -= sizeof(*nd_ns); - - nd6_option_init(nd_ns + 1, icmp6len, &ndopts); - if (nd6_options(&ndopts) < 0) - goto failed; - - if (!ndopts.nd_opts_src_lladdr) - goto failed; - - lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); - lladdrlen = (ndopts.nd_opts_src_lladdr->nd_opt_len << 3) - 2; - - /* switch(4) only supports Ethernet interfaces */ - if (lladdrlen != ETHER_ADDR_LEN) - goto failed; - memcpy(lladdr, pre_swfcl->swfcl_nd6->nd6_lladdr, - ETHER_ADDR_LEN); - break; - } - - memcpy(swfcl->swfcl_nd6, pre_swfcl->swfcl_nd6, - sizeof(*swfcl->swfcl_nd6)); - - return (m); - - failed: - m_freem(m); - return (NULL); -} - -struct mbuf * -swofp_apply_set_field_icmpv6(struct mbuf *m, int off, - struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl) -{ - struct icmp6_hdr *icmp6; - - IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6)); - if (icmp6 == NULL) - return (NULL); /* m was already freed */ - - if (pre_swfcl->swfcl_icmpv6) { - icmp6->icmp6_type = pre_swfcl->swfcl_icmpv6->icmpv6_type; - icmp6->icmp6_code = pre_swfcl->swfcl_icmpv6->icmpv6_code; - - memcpy(swfcl->swfcl_icmpv6, pre_swfcl->swfcl_icmpv6, - sizeof(*swfcl->swfcl_icmpv6)); - } - - m->m_pkthdr.csum_flags |= M_ICMP_CSUM_OUT; - - switch (icmp6->icmp6_type) { - case ND_NEIGHBOR_ADVERT: - case ND_NEIGHBOR_SOLICIT: - return swofp_apply_set_field_nd6(m, off, pre_swfcl, swfcl); - } - - return (m); -} -#endif /* INET6 */ - -struct mbuf * -swofp_apply_set_field_icmpv4(struct mbuf *m, int off, - struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl) -{ - struct icmp *icmp; - - if (m->m_len < (off + ICMP_MINLEN) && - (m = m_pullup(m, (off + ICMP_MINLEN))) == NULL) - return NULL; - - icmp = (struct icmp *)((m)->m_data + off); - - if (pre_swfcl->swfcl_icmpv4) { - icmp->icmp_type = pre_swfcl->swfcl_icmpv4->icmpv4_type; - icmp->icmp_code = pre_swfcl->swfcl_icmpv4->icmpv4_code; - - memcpy(swfcl->swfcl_icmpv4, pre_swfcl->swfcl_icmpv4, - sizeof(*swfcl->swfcl_icmpv4)); - } - - m->m_pkthdr.csum_flags |= M_ICMP_CSUM_OUT; - - return (m); -} - -#ifdef INET6 -struct mbuf * -swofp_apply_set_field_ipv6(struct mbuf *m, int off, - struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl) -{ - struct ip6_hdr *ip6; - int hlen; - /* max size is 802.1ad header size */ - u_char eh_bk[sizeof(struct ether_vlan_header) + EVL_ENCAPLEN]; - - if (m->m_len < (off + sizeof(*ip6)) && - (m = m_pullup(m, off + sizeof(*ip6))) == NULL) - return (NULL); - - ip6 = (struct ip6_hdr *)(mtod(m, caddr_t) + off); - - if (pre_swfcl->swfcl_ipv6) { - /* set version, class and flow label at once */ - ip6->ip6_flow = (IPV6_VERSION | - (pre_swfcl->swfcl_ipv6->ipv6_flow_label & - IPV6_FLOWLABEL_MASK) | - htonl(pre_swfcl->swfcl_ipv6->ipv6_tclass << 20)); - ip6->ip6_hlim = pre_swfcl->swfcl_ipv6->ipv6_hlimit; - ip6->ip6_nxt = pre_swfcl->swfcl_ipv6->ipv6_nxt; - - ip6->ip6_src = pre_swfcl->swfcl_ipv6->ipv6_src; - ip6->ip6_dst = pre_swfcl->swfcl_ipv6->ipv6_dst; - - memcpy(pre_swfcl->swfcl_ipv6, swfcl->swfcl_ipv6, - sizeof(*pre_swfcl->swfcl_ipv6)); - } - - hlen = sizeof(*ip6); - - switch (swfcl->swfcl_ipv6->ipv6_nxt) { - case IPPROTO_UDP: - m = swofp_apply_set_field_udp(m, (off + hlen), - pre_swfcl, swfcl); - if (m == NULL) - return (NULL); - m->m_pkthdr.csum_flags |= M_UDP_CSUM_OUT; - break; - case IPPROTO_TCP: - m = swofp_apply_set_field_tcp(m, (off + hlen), - pre_swfcl, swfcl); - if (m == NULL) - return (NULL); - m->m_pkthdr.csum_flags |= M_TCP_CSUM_OUT; - break; - case IPPROTO_ICMPV6: - m = swofp_apply_set_field_icmpv6(m, (off + hlen), - pre_swfcl, swfcl); - if (m == NULL) - return (NULL); - break; - } - - /* - * Recalculate checksums: - * It doesn't use H/W offload because doesn't know to send a frame - * from which interface. - */ - m_copydata(m, 0, off, eh_bk); - m_adj(m, off); - - if (m->m_len < hlen && ((m = m_pullup(m, hlen)) == NULL)) - return (NULL); - - in6_proto_cksum_out(m, NULL); - - M_PREPEND(m, off, M_DONTWAIT); - if (m == NULL) - return (NULL); - - m_copyback(m, 0, off, eh_bk, M_DONTWAIT); - - return (m); -} -#endif /* INET6 */ - -struct mbuf * -swofp_apply_set_field_ipv4(struct mbuf *m, int off, - struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl) -{ - struct ip *ip; - int hlen; - /* max size is 802.1ad header size */ - u_char eh_bk[sizeof(struct ether_vlan_header) + EVL_ENCAPLEN]; - - if (m->m_len < (off + sizeof(*ip)) && - (m = m_pullup(m, off + sizeof(*ip))) == NULL) - return (NULL); - - ip = (struct ip *)(mtod(m, caddr_t) + off); - - if (pre_swfcl->swfcl_ipv4) { - ip->ip_p = pre_swfcl->swfcl_ipv4->ipv4_proto; - ip->ip_tos = pre_swfcl->swfcl_ipv4->ipv4_tos; - - memcpy(&ip->ip_src.s_addr, &pre_swfcl->swfcl_ipv4->ipv4_src, - sizeof(uint32_t)); - memcpy(&ip->ip_dst.s_addr, &pre_swfcl->swfcl_ipv4->ipv4_dst, - sizeof(uint32_t)); - - memcpy(pre_swfcl->swfcl_ipv4, swfcl->swfcl_ipv4, - sizeof(*pre_swfcl->swfcl_ipv4)); - } - - hlen = (ip->ip_hl << 2); - - switch (swfcl->swfcl_ipv4->ipv4_proto) { - case IPPROTO_UDP: - m = swofp_apply_set_field_udp(m, (off + hlen), - pre_swfcl, swfcl); - if (m == NULL) - return (NULL); - m->m_pkthdr.csum_flags |= M_UDP_CSUM_OUT; - break; - case IPPROTO_TCP: - m = swofp_apply_set_field_tcp(m, (off + hlen), - pre_swfcl, swfcl); - if (m == NULL) - return (NULL); - m->m_pkthdr.csum_flags |= M_TCP_CSUM_OUT; - break; - case IPPROTO_ICMP: - m = swofp_apply_set_field_icmpv4(m, (off + hlen), - pre_swfcl, swfcl); - if (m == NULL) - return (NULL); - break; - } - - /* - * Recalculate checksums: - * It doesn't use H/W offload because doesn't know to send a frame - * from which interface. - */ - m_copydata(m, 0, off, eh_bk); - m_adj(m, off); - - if (m->m_len < hlen && ((m = m_pullup(m, hlen)) == NULL)) - return (NULL); - ip = mtod(m, struct ip *); - - ip->ip_sum = 0; - in_proto_cksum_out(m, NULL); - ip->ip_sum = in_cksum(m, hlen); - - M_PREPEND(m, off, M_DONTWAIT); - if (m == NULL) - return (NULL); - - m_copyback(m, 0, off, eh_bk, M_DONTWAIT); - - return (m); -} - -struct mbuf * -swofp_apply_set_field_arp( struct mbuf *m, int off, - struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl) -{ - struct ether_arp *ea; - - if (m->m_len < (off + sizeof(*ea)) && - (m = m_pullup(m, off + sizeof(*ea))) == NULL) - return (NULL); - - ea = (struct ether_arp *)((m)->m_data + off); - - if (pre_swfcl->swfcl_arp) { - ea->arp_op = pre_swfcl->swfcl_arp->_arp_op; - - memcpy(&ea->arp_sha, pre_swfcl->swfcl_arp->arp_sha, - ETHER_ADDR_LEN); - memcpy(&ea->arp_tha, pre_swfcl->swfcl_arp->arp_tha, - ETHER_ADDR_LEN); - memcpy(&ea->arp_spa, &pre_swfcl->swfcl_arp->arp_sip, - sizeof(uint32_t)); - memcpy(&ea->arp_tpa, &pre_swfcl->swfcl_arp->arp_tip, - sizeof(uint32_t)); - memcpy(swfcl->swfcl_arp, pre_swfcl->swfcl_arp, - sizeof(*swfcl->swfcl_arp)); - } - - return (m); -} - -struct mbuf * -swofp_apply_set_field_ether(struct mbuf *m, int off, - struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl) -{ - struct ether_header *eh; - struct ether_vlan_header *evl = NULL; - uint16_t *ether_type; - - m = swofp_expand_8021q_tag(m); - if (m == NULL) - return (NULL); - - /* - * pullup to maximum size QinQ header - */ - if ((m = m_pullup(m, (sizeof(*evl) + EVL_ENCAPLEN))) == NULL) - return (NULL); - - eh = mtod(m, struct ether_header *); - - switch (ntohs(eh->ether_type)) { - case ETHERTYPE_QINQ: - off = EVL_ENCAPLEN + sizeof(struct ether_vlan_header); - evl = mtod(m, struct ether_vlan_header *); - ether_type = (uint16_t *)(mtod(m, caddr_t) + EVL_ENCAPLEN + - offsetof(struct ether_vlan_header, evl_proto)); - break; - case ETHERTYPE_VLAN: - off = sizeof(struct ether_vlan_header); - evl = mtod(m, struct ether_vlan_header *); - ether_type = &evl->evl_proto; - break; - default: - off = sizeof(struct ether_header); - ether_type = &eh->ether_type; - break; - } - - if (pre_swfcl->swfcl_vlan) { - switch (ntohs(eh->ether_type)) { - case ETHERTYPE_QINQ: - case ETHERTYPE_VLAN: - evl->evl_tag = (pre_swfcl->swfcl_vlan->vlan_vid | - htons(pre_swfcl->swfcl_vlan->vlan_pcp << - EVL_PRIO_BITS)); - break; - default: - break; - } - - /* Update the classifier if it exists. */ - if (swfcl->swfcl_vlan) - memcpy(swfcl->swfcl_vlan, pre_swfcl->swfcl_vlan, - sizeof(*swfcl->swfcl_vlan)); - } - - if (pre_swfcl->swfcl_ether) { - memcpy(eh->ether_shost, pre_swfcl->swfcl_ether->eth_src, - ETHER_ADDR_LEN); - memcpy(eh->ether_dhost, pre_swfcl->swfcl_ether->eth_dst, - ETHER_ADDR_LEN); - *ether_type = pre_swfcl->swfcl_ether->eth_type; - memcpy(swfcl->swfcl_ether, pre_swfcl->swfcl_ether, - sizeof(*swfcl->swfcl_ether)); - } - - switch (ntohs(*ether_type)) { - case ETHERTYPE_ARP: - return swofp_apply_set_field_arp(m, off, pre_swfcl, swfcl); - case ETHERTYPE_IP: - return swofp_apply_set_field_ipv4(m, off, pre_swfcl, swfcl); -#ifdef INET6 - case ETHERTYPE_IPV6: - return swofp_apply_set_field_ipv6(m, off, pre_swfcl, swfcl); -#endif /* INET6 */ - case ETHERTYPE_MPLS: - /* unsupported yet */ - break; - } - - return (m); -} - -struct mbuf * -swofp_apply_set_field_tunnel(struct mbuf *m, int off, - struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl) -{ - struct bridge_tunneltag *brtag; - - if (pre_swfcl->swfcl_tunnel) { - if ((brtag = bridge_tunneltag(m)) == NULL) { - m_freem(m); - return (NULL); - } - - brtag->brtag_id = be64toh(pre_swfcl->swfcl_tunnel->tun_key); - - if (pre_swfcl->swfcl_tunnel->tun_ipv4_dst.s_addr != - INADDR_ANY) { - brtag->brtag_peer.sin.sin_family = - brtag->brtag_local.sin.sin_family = AF_INET; - brtag->brtag_local.sin.sin_addr = - pre_swfcl->swfcl_tunnel->tun_ipv4_src; - brtag->brtag_peer.sin.sin_addr = - pre_swfcl->swfcl_tunnel->tun_ipv4_dst; - } else if (!IN6_IS_ADDR_UNSPECIFIED( - &pre_swfcl->swfcl_tunnel->tun_ipv6_dst)) { - brtag->brtag_peer.sin6.sin6_family = - brtag->brtag_local.sin.sin_family = AF_INET6; - brtag->brtag_local.sin6.sin6_addr = - pre_swfcl->swfcl_tunnel->tun_ipv6_src; - brtag->brtag_peer.sin6.sin6_addr = - pre_swfcl->swfcl_tunnel->tun_ipv6_dst; - } else { - bridge_tunneluntag(m); - m_freem(m); - return (NULL); - } - - /* - * It can't be used by apply-action instruction. - */ - if (swfcl->swfcl_tunnel) { - memcpy(swfcl->swfcl_tunnel, pre_swfcl->swfcl_tunnel, - sizeof(*pre_swfcl->swfcl_tunnel)); - } - } - - return swofp_apply_set_field_ether(m, 0, pre_swfcl, swfcl); -} - -struct mbuf * -swofp_apply_set_field(struct mbuf *m, struct swofp_pipeline_desc *swpld) -{ - return swofp_apply_set_field_tunnel(m, 0, - &swpld->swpld_pre_swfcl, swpld->swpld_swfcl); -} - -struct mbuf * -swofp_action_set_field(struct switch_softc *sc, struct mbuf *m, - struct swofp_pipeline_desc *swpld, struct ofp_action_header *oah) -{ - struct ofp_oxm_class *oxm_handler; - struct ofp_action_set_field *oasf; - struct ofp_ox_match *oxm; - struct switch_flow_classify *swfcl, *pre_swfcl; - - oasf = (struct ofp_action_set_field *)oah; - oxm = (struct ofp_ox_match *)oasf->asf_field; - - oxm_handler = swofp_lookup_oxm_handler(oxm); - if ((oxm_handler == NULL) || - (oxm_handler->oxm_set == NULL)) - goto failed; - - swfcl = swpld->swpld_swfcl; - pre_swfcl = &swpld->swpld_pre_swfcl; - - if (oxm->oxm_class == htons(OFP_OXM_C_NXM_1)) { - switch (OFP_OXM_GET_FIELD(oxm)) { - case OFP_XM_NXMT_TUNNEL_ID: /* alias OFP_XM_T_TUNNEL_ID */ - case OFP_XM_NXMT_TUNNEL_IPV4_SRC: - case OFP_XM_NXMT_TUNNEL_IPV4_DST: - case OFP_XM_NXMT_TUNNEL_IPV6_SRC: - case OFP_XM_NXMT_TUNNEL_IPV6_DST: - if (pre_swfcl->swfcl_tunnel) - break; - pre_swfcl->swfcl_tunnel = pool_get(&swfcl_pool, - PR_NOWAIT|PR_ZERO); - if (pre_swfcl->swfcl_tunnel == NULL) - goto failed; - if (swfcl->swfcl_tunnel) - memcpy(pre_swfcl->swfcl_tunnel, - swfcl->swfcl_tunnel, - sizeof(*swfcl->swfcl_tunnel)); - break; - } - } else { - switch (OFP_OXM_GET_FIELD(oxm)) { - case OFP_XM_T_ETH_SRC: - case OFP_XM_T_ETH_DST: - case OFP_XM_T_ETH_TYPE: - if (pre_swfcl->swfcl_ether) - break; - pre_swfcl->swfcl_ether = pool_get(&swfcl_pool, - PR_NOWAIT|PR_ZERO); - if (pre_swfcl->swfcl_ether == NULL) - goto failed; - memcpy(pre_swfcl->swfcl_ether, swfcl->swfcl_ether, - sizeof(*swfcl->swfcl_ether)); - break; - case OFP_XM_T_VLAN_VID: - case OFP_XM_T_VLAN_PCP: - if (pre_swfcl->swfcl_vlan) - break; - pre_swfcl->swfcl_vlan = pool_get(&swfcl_pool, - PR_NOWAIT|PR_ZERO); - if (pre_swfcl->swfcl_vlan == NULL) - goto failed; - if (swfcl->swfcl_vlan) - memcpy(pre_swfcl->swfcl_vlan, swfcl->swfcl_vlan, - sizeof(*swfcl->swfcl_vlan)); - break; - case OFP_XM_T_ARP_SHA: - case OFP_XM_T_ARP_THA: - case OFP_XM_T_ARP_SPA: - case OFP_XM_T_ARP_TPA: - case OFP_XM_T_ARP_OP: - if (pre_swfcl->swfcl_arp) - break; - pre_swfcl->swfcl_arp = pool_get(&swfcl_pool, - PR_NOWAIT|PR_ZERO); - if (swfcl->swfcl_arp == NULL) - goto failed; - memcpy(pre_swfcl->swfcl_arp, swfcl->swfcl_arp, - sizeof(*swfcl->swfcl_arp)); - break; - case OFP_XM_T_IP_DSCP: - case OFP_XM_T_IP_ECN: - case OFP_XM_T_IP_PROTO: - if (swfcl->swfcl_ipv4) { - if (pre_swfcl->swfcl_ipv4) - break; - pre_swfcl->swfcl_ipv4 = pool_get(&swfcl_pool, - PR_NOWAIT|PR_ZERO); - if (pre_swfcl->swfcl_ipv4 == NULL) - goto failed; - memcpy(pre_swfcl->swfcl_ipv4, swfcl->swfcl_ipv4, - sizeof(*swfcl->swfcl_ipv4)); - } else if (swfcl->swfcl_ipv6) { - if (pre_swfcl->swfcl_ipv6) - break; - pre_swfcl->swfcl_ipv6 = pool_get(&swfcl_pool, - PR_NOWAIT|PR_ZERO); - if (pre_swfcl->swfcl_ipv6 == NULL) - goto failed; - memcpy(pre_swfcl->swfcl_ipv6, swfcl->swfcl_ipv6, - sizeof(*swfcl->swfcl_ipv6)); - } - break; - case OFP_XM_T_IPV4_SRC: - case OFP_XM_T_IPV4_DST: - if (pre_swfcl->swfcl_ipv4) - break; - pre_swfcl->swfcl_ipv4 = pool_get(&swfcl_pool, - PR_NOWAIT|PR_ZERO); - if (pre_swfcl->swfcl_ipv4 == NULL) - goto failed; - memcpy(pre_swfcl->swfcl_ipv4, swfcl->swfcl_ipv4, - sizeof(*swfcl->swfcl_ipv4)); - break; - case OFP_XM_T_IPV6_SRC: - case OFP_XM_T_IPV6_DST: - case OFP_XM_T_IPV6_FLABEL: - if (pre_swfcl->swfcl_ipv6) - break; - pre_swfcl->swfcl_ipv6 = pool_get(&swfcl_pool, - PR_NOWAIT|PR_ZERO); - if (pre_swfcl->swfcl_ipv6 == NULL) - goto failed; - memcpy(pre_swfcl->swfcl_ipv6, swfcl->swfcl_ipv6, - sizeof(*swfcl->swfcl_ipv6)); - break; - case OFP_XM_T_UDP_SRC: - case OFP_XM_T_UDP_DST: - if (pre_swfcl->swfcl_udp) - break; - pre_swfcl->swfcl_udp = pool_get(&swfcl_pool, - PR_NOWAIT|PR_ZERO); - if (pre_swfcl->swfcl_udp == NULL) - goto failed; - memcpy(pre_swfcl->swfcl_udp, swfcl->swfcl_udp, - sizeof(*swfcl->swfcl_udp)); - break; - case OFP_XM_T_TCP_SRC: - case OFP_XM_T_TCP_DST: - if (pre_swfcl->swfcl_tcp) - break; - pre_swfcl->swfcl_tcp = pool_get(&swfcl_pool, - PR_NOWAIT|PR_ZERO); - if (pre_swfcl->swfcl_tcp == NULL) - goto failed; - memcpy(pre_swfcl->swfcl_tcp, swfcl->swfcl_tcp, - sizeof(*swfcl->swfcl_tcp)); - break; - case OFP_XM_T_ICMPV4_CODE: - case OFP_XM_T_ICMPV4_TYPE: - if (pre_swfcl->swfcl_icmpv4) - break; - pre_swfcl->swfcl_icmpv4 = pool_get(&swfcl_pool, - PR_NOWAIT|PR_ZERO); - if (pre_swfcl->swfcl_icmpv4 == NULL) - goto failed; - memcpy(pre_swfcl->swfcl_icmpv4, swfcl->swfcl_icmpv4, - sizeof(*swfcl->swfcl_icmpv4)); - break; - case OFP_XM_T_ICMPV6_CODE: - case OFP_XM_T_ICMPV6_TYPE: - if (pre_swfcl->swfcl_icmpv6) - break; - pre_swfcl->swfcl_icmpv6 = pool_get(&swfcl_pool, - PR_NOWAIT|PR_ZERO); - if (pre_swfcl->swfcl_icmpv6 == NULL) - goto failed; - memcpy(pre_swfcl->swfcl_icmpv6, swfcl->swfcl_icmpv6, - sizeof(*swfcl->swfcl_icmpv6)); - break; - case OFP_XM_T_IPV6_ND_SLL: - case OFP_XM_T_IPV6_ND_TLL: - case OFP_XM_T_IPV6_ND_TARGET: - if (pre_swfcl->swfcl_nd6) - break; - pre_swfcl->swfcl_nd6 = pool_get(&swfcl_pool, - PR_NOWAIT|PR_ZERO); - if (pre_swfcl->swfcl_nd6 == NULL) - goto failed; - memcpy(pre_swfcl->swfcl_nd6, swfcl->swfcl_nd6, - sizeof(*swfcl->swfcl_nd6)); - break; - case OFP_XM_T_TUNNEL_ID: /* alias OFP_XM_T_TUNNEL_ID */ - if (pre_swfcl->swfcl_tunnel) - break; - pre_swfcl->swfcl_tunnel = pool_get(&swfcl_pool, - PR_NOWAIT|PR_ZERO); - if (pre_swfcl->swfcl_tunnel == NULL) - goto failed; - if (swfcl->swfcl_tunnel) - memcpy(pre_swfcl->swfcl_tunnel, - swfcl->swfcl_tunnel, - sizeof(*swfcl->swfcl_tunnel)); - break; - } - } - - if (oxm_handler->oxm_set(pre_swfcl, oxm)) - goto failed; - - return (m); - failed: - m_freem(m); - return (NULL); -} - -struct mbuf * -swofp_execute_action(struct switch_softc *sc, struct mbuf *m, - struct swofp_pipeline_desc *swpld, struct ofp_action_header *oah) -{ - struct ofp_action_handler *handler; - - handler = swofp_lookup_action_handler(ntohs(oah->ah_type)); - if ((handler == NULL) || (handler->action == NULL)) { - DPRINTF(sc, "unknown action (type %d)\n", - ntohs(oah->ah_type)); - m_freem(m); - return (NULL); - } - - m = handler->action(sc, m, swpld, oah); - if (m == NULL) - return (NULL); - - return (m); -} - -struct mbuf * -swofp_execute_action_set_field(struct switch_softc *sc, struct mbuf *m, - struct swofp_pipeline_desc *swpld, struct ofp_action_header *oah) -{ - struct ofp_action_header **set_fields; - int i; - - set_fields = (struct ofp_action_header **)oah; - - for (i = 0; i < OFP_XM_T_MAX; i++) { - if (set_fields[i] == NULL) - continue; - - m = swofp_execute_action(sc, m, swpld, set_fields[i]); - if (m == NULL) - return (NULL); - } - - return (m); -} - - -struct mbuf * -swofp_execute_action_set(struct switch_softc *sc, struct mbuf *m, - struct swofp_pipeline_desc *swpld) -{ - struct swofp_action_set *swas; - int i; - - TAILQ_INIT(&swpld->swpld_fwdp_q); - swas = swpld->swpld_action_set; - swpld->swpld_swfcl->swfcl_cookie = UINT64_MAX; - - for (i = 0 ; i < nitems(ofp_action_handlers); i++) { - if (swas[i].swas_action == NULL) - continue; - - if (swas[i].swas_type == OFP_ACTION_SET_FIELD) - m = swofp_execute_action_set_field(sc, m, swpld, - swas[i].swas_action); - else - m = swofp_execute_action(sc, m, swpld, - swas[i].swas_action); - - if (m == NULL) - break; - } - - m_freem(m); - - return (NULL); -} - -struct mbuf * -swofp_apply_actions(struct switch_softc *sc, struct mbuf *m, - struct swofp_pipeline_desc *swpld, struct ofp_instruction_actions *oia) -{ - struct ofp_action_header *oah; - - TAILQ_INIT(&swpld->swpld_fwdp_q); - - OFP_I_ACTIONS_FOREACH(oia, oah) { - m = swofp_execute_action(sc, m, swpld, oah); - if (m == NULL) - return (NULL); - } - - return (m); -} - -struct swofp_action_set * -swofp_lookup_action_set(struct swofp_pipeline_desc *swpld, uint16_t type) -{ - int i; - - for (i = 0; i < nitems(ofp_action_handlers); i ++) { - if (swpld->swpld_action_set[i].swas_type == type) - return (&swpld->swpld_action_set[i]); - } - - return (NULL); -} - -void -swofp_write_actions_set_field(struct swofp_action_set *swas, - struct ofp_action_header *oah) -{ - struct ofp_action_header **set_fields; - struct ofp_action_set_field *oasf; - struct ofp_ox_match *oxm; - - set_fields = (struct ofp_action_header **)swas->swas_action; - - oasf = (struct ofp_action_set_field *)oah; - oxm = (struct ofp_ox_match *)oasf->asf_field; - - set_fields[OFP_OXM_GET_FIELD(oxm)] = oah; -} - -int -swofp_write_actions(struct ofp_instruction_actions *oia, - struct swofp_pipeline_desc *swpld) -{ - struct swofp_action_set *swas; - struct ofp_action_header *oah; - - OFP_I_ACTIONS_FOREACH(oia, oah) { - swas = swofp_lookup_action_set(swpld, ntohs(oah->ah_type)); - if (swas == NULL) - return (ENOENT); - - if (ntohs(oah->ah_type) == OFP_ACTION_SET_FIELD) - swofp_write_actions_set_field(swas, oah); - else - swas->swas_action = oah; - } - - return (0); -} - -void -swofp_clear_actions_set_field(struct swofp_action_set *swas, - struct ofp_action_header *oah) -{ - struct ofp_action_header **set_fields; - struct ofp_action_set_field *oasf; - struct ofp_ox_match *oxm; - - set_fields = (struct ofp_action_header **)swas->swas_action; - - oasf = (struct ofp_action_set_field *)oah; - oxm = (struct ofp_ox_match *)oasf->asf_field; - - set_fields[OFP_OXM_GET_FIELD(oxm)] = NULL; -} - -int -swofp_clear_actions(struct ofp_instruction_actions *oia, - struct swofp_pipeline_desc *swpld) -{ - struct swofp_action_set *swas; - struct ofp_action_header *oah; - - OFP_I_ACTIONS_FOREACH(oia, oah) { - swas = swofp_lookup_action_set(swpld, ntohs(oah->ah_type)); - if (swas == NULL) - return (ENOENT); - - if (ntohs(oah->ah_type) == OFP_ACTION_SET_FIELD) - swofp_clear_actions_set_field(swas, oah); - else - swas->swas_action = NULL; - } - - return (0); -} - -void -swofp_write_metadata(struct ofp_instruction_write_metadata *iowm, - struct swofp_pipeline_desc *swpld) -{ - uint64_t val, mask; - - val = iowm->iwm_metadata; - mask = iowm->iwm_metadata_mask; - - swpld->swpld_metadata = (val & mask); -} - -void -swofp_forward_ofs(struct switch_softc *sc, struct switch_flow_classify *swfcl, - struct mbuf *m) -{ - struct swofp_ofs *ofs = sc->sc_ofs; - struct swofp_flow_entry *swfe; - struct swofp_flow_table *swft; - struct swofp_pipeline_desc *swpld; - int error; - uint8_t next_table_id = 0; - - swpld = swofp_pipeline_desc_create(swfcl); - if (swpld == NULL) { - m_freem(m); - return; - } - - TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) { - if (swft->swft_table_id != next_table_id) - continue; - - /* XXX - * The metadata is pipeline parameters but it uses same match - * framework for matching so it is copy to flow classify. - */ - swpld->swpld_swfcl->swfcl_metadata = swpld->swpld_metadata; - - if ((swfe = swofp_flow_lookup(swft, - swpld->swpld_swfcl)) == NULL) - break; - - /* Set pipeline parameters */ - swpld->swpld_cookie = swfe->swfe_cookie; - swpld->swpld_table_id = swft->swft_table_id; - swpld->swpld_tablemiss = swfe->swfe_tablemiss; - - /* Update statistics */ - nanouptime(&swfe->swfe_idle_time); - swfe->swfe_packet_cnt++; - swfe->swfe_byte_cnt += m->m_pkthdr.len; - - if (swfe->swfe_meter) { - /* TODO: Here is meter instruction */ - } - - if (swfe->swfe_apply_actions) { - m = swofp_apply_actions(sc, m, swpld, - swfe->swfe_apply_actions); - if (m == NULL) - goto out; - } - - if (swfe->swfe_clear_actions) { - error = swofp_clear_actions( - swfe->swfe_clear_actions, swpld); - if (error) - goto out; - } - - if (swfe->swfe_write_actions) { - error = swofp_write_actions( - swfe->swfe_write_actions, swpld); - if (error) - goto out; - } - - if (swfe->swfe_write_metadata) - swofp_write_metadata(swfe->swfe_write_metadata, swpld); - - if (swfe->swfe_goto_table) - next_table_id = swfe->swfe_goto_table->igt_table_id; - else - break; - } - - m = swofp_execute_action_set(sc, m, swpld); - out: - m_freem(m); - swofp_pipeline_desc_destroy(swpld); -} - -int -swofp_input(struct switch_softc *sc, struct mbuf *m) -{ -#if NBPFILTER > 0 - struct swofp_ofs *swofs = sc->sc_ofs; -#endif - struct ofp_header *oh; - ofp_msg_handler handler; - uint16_t ohlen; - - if (m->m_len < sizeof(*oh) && - (m = m_pullup(m, sizeof(*oh))) == NULL) - return (ENOBUFS); - - oh = mtod(m, struct ofp_header *); - - ohlen = ntohs(oh->oh_length); - /* Validate that we have a sane header. */ - KASSERT(m->m_flags & M_PKTHDR); - if (ohlen < sizeof(*oh) || m->m_pkthdr.len < ohlen) { - swofp_send_error(sc, m, OFP_ERRTYPE_BAD_REQUEST, - OFP_ERRREQ_BAD_LEN); - return (0); - } - - if (m->m_len < ohlen && (m = m_pullup(m, ohlen)) == NULL) - return (ENOBUFS); - -#if NBPFILTER > 0 - if (sc->sc_ofbpf) - switch_mtap(sc->sc_ofbpf, m, BPF_DIRECTION_IN, - swofs->swofs_datapath_id); -#endif - - handler = swofp_lookup_msg_handler(oh->oh_type); - if (handler) - (*handler)(sc, m); - else - swofp_send_error(sc, m, OFP_ERRTYPE_BAD_REQUEST, - OFP_ERRREQ_TYPE); - - return (0); -} - -int -swofp_output(struct switch_softc *sc, struct mbuf *m) -{ -#if NBPFILTER > 0 - struct swofp_ofs *swofs = sc->sc_ofs; -#endif - - if (sc->sc_swdev == NULL) { - m_freem(m); - return (ENXIO); - } - -#if NBPFILTER > 0 - if (sc->sc_ofbpf) - switch_mtap(sc->sc_ofbpf, m, BPF_DIRECTION_OUT, - swofs->swofs_datapath_id); -#endif - - if (sc->sc_swdev->swdev_output(sc, m) != 0) - return (ENOBUFS); - - return (0); -} - -/* - * OpenFlow protocol HELLO message handler - */ -int -swofp_recv_hello(struct switch_softc *sc, struct mbuf *m) -{ - struct ofp_header *oh; - - oh = mtod(m, struct ofp_header *); - - if (oh->oh_version != OFP_V_1_3) - swofp_send_error(sc, m, - OFP_ERRTYPE_HELLO_FAILED, OFP_ERRHELLO_INCOMPATIBLE); - else - m_freem(m); - - return (0); -} - -void -swofp_send_hello(struct switch_softc *sc) -{ - struct swofp_ofs *swofs = sc->sc_ofs; - struct mbuf *m; - struct ofp_header *oh; - - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) - return; /* XXX */ - - oh = mtod(m, struct ofp_header *); - - oh->oh_version = OFP_V_1_3; - oh->oh_type = OFP_T_HELLO; - oh->oh_length = htons(sizeof(*oh)); - oh->oh_xid = htonl(swofs->swofs_xidnxt++); - m->m_len = m->m_pkthdr.len = sizeof(*oh); - - (void)swofp_output(sc, m); -} - -/* - * OpenFlow protocol Error message - */ -void -swofp_send_error(struct switch_softc *sc, struct mbuf *m, - uint16_t type, uint16_t code) -{ - struct mbuf *n; - struct ofp_header *oh; - struct ofp_error *oe; - int off; - uint32_t xid; - uint16_t len; - - /* Reuse mbuf from request message */ - oh = mtod(m, struct ofp_header *); - - /* Save data for the response and copy back later. */ - len = min(ntohs(oh->oh_length), OFP_ERRDATA_MAX); - if (len < m->m_pkthdr.len) - m_adj(m, len - m->m_pkthdr.len); - xid = oh->oh_xid; - - if ((n = m_makespace(m, 0, sizeof(struct ofp_error), &off)) == NULL) { - m_freem(m); - return; - } - /* if skip is 0, off is also 0 */ - KASSERT(off == 0); - - oe = mtod(n, struct ofp_error *); - - oe->err_oh.oh_version = OFP_V_1_3; - oe->err_oh.oh_type = OFP_T_ERROR; - oe->err_oh.oh_length = htons(sizeof(struct ofp_error) + len); - oe->err_oh.oh_xid = xid; - oe->err_type = htons(type); - oe->err_code = htons(code); - - (void)swofp_output(sc, m); -} - - -/* - * OpenFlow protocol Echo message - */ -int -swofp_recv_echo(struct switch_softc *sc, struct mbuf *m) -{ - return swofp_send_echo(sc, m); -} - -int -swofp_send_echo(struct switch_softc *sc, struct mbuf *m) -{ - struct ofp_header *oh; - - oh = mtod(m, struct ofp_header *); - oh->oh_type = OFP_T_ECHO_REPLY; - - return (swofp_output(sc, m)); -} - - -/* - * Feature request handler - */ -int -swofp_recv_features_req(struct switch_softc *sc, struct mbuf *m) -{ - - struct swofp_ofs *swofs = sc->sc_ofs; - struct ofp_header *oh; - struct ofp_switch_features swf; - - oh = mtod(m, struct ofp_header *); - - memset(&swf, 0, sizeof(swf)); - memcpy(&swf, oh, sizeof(*oh)); - swf.swf_oh.oh_type = OFP_T_FEATURES_REPLY; - swf.swf_oh.oh_length = htons(sizeof(swf)); - - swf.swf_datapath_id = htobe64(swofs->swofs_datapath_id); - swf.swf_nbuffers = htonl(0); /* no buffer now */ - swf.swf_ntables = OFP_TABLE_ID_MAX; - swf.swf_aux_id = 0; - swf.swf_capabilities = htonl(OFP_SWCAP_FLOW_STATS | - OFP_SWCAP_TABLE_STATS | OFP_SWCAP_PORT_STATS | - OFP_SWCAP_GROUP_STATS); - - m_copyback(m, 0, sizeof(swf), (caddr_t)&swf, M_WAIT); - - return (swofp_output(sc, m)); -} - -/* - * Get config handler - */ -int -swofp_recv_config_req(struct switch_softc *sc, struct mbuf *m) -{ - struct swofp_ofs *swofs = sc->sc_ofs; - struct ofp_switch_config osc; - - memcpy(&osc.cfg_oh, mtod(m, caddr_t), sizeof(struct ofp_header)); - osc.cfg_oh.oh_type = OFP_T_GET_CONFIG_REPLY; - osc.cfg_oh.oh_length = htons(sizeof(osc)); - - osc.cfg_flags = htons(swofs->swofs_switch_config.cfg_flags); - osc.cfg_miss_send_len = - htons(swofs->swofs_switch_config.cfg_miss_send_len); - if (m_copyback(m, 0, sizeof(osc), &osc, M_NOWAIT)) { - m_freem(m); - return (-1); - } - - return (swofp_output(sc, m)); -} - -/* - * Set config handler - */ -int -swofp_recv_set_config(struct switch_softc *sc, struct mbuf *m) -{ - struct swofp_ofs *swofs = sc->sc_ofs; - struct ofp_switch_config *swc; - - swc = mtod(m, struct ofp_switch_config *); - if (ntohs(swc->cfg_oh.oh_length) < sizeof(*swc)) { - swofp_send_error(sc, m, OFP_ERRTYPE_BAD_REQUEST, - OFP_ERRREQ_BAD_LEN); - return (-1); - } - - /* - * Support only "normal" fragment handle - */ - swofs->swofs_switch_config.cfg_flags = OFP_CONFIG_FRAG_NORMAL; - swofs->swofs_switch_config.cfg_miss_send_len = - ntohs(swc->cfg_miss_send_len); - - m_freem(m); - - return (0); -} - -/* - * OpenFlow protocol FLOW REMOVE message handlers - */ -int -swofp_send_flow_removed(struct switch_softc *sc, struct swofp_flow_entry *swfe, - uint8_t reason) -{ - struct ofp_flow_removed *ofr; - struct timespec now, duration; - struct mbuf *m; - int match_len; - - match_len = ntohs(swfe->swfe_match->om_length); - - MGETHDR(m, M_WAITOK, MT_DATA); - if (m == NULL) - return (ENOBUFS); - if ((sizeof(*ofr) + match_len) >= MHLEN) { - MCLGET(m, M_WAITOK); - if ((m->m_flags & M_EXT) == 0) { - m_freem(m); - return (ENOBUFS); - } - } - - ofr = mtod(m, struct ofp_flow_removed *); - - ofr->fr_oh.oh_version = OFP_V_1_3; - ofr->fr_oh.oh_type = OFP_T_FLOW_REMOVED; - ofr->fr_oh.oh_xid = htonl(sc->sc_ofs->swofs_xidnxt++); - - ofr->fr_cookie = htobe64(swfe->swfe_cookie); - ofr->fr_priority = htons(swfe->swfe_priority); - ofr->fr_reason = reason; - ofr->fr_table_id = swfe->swfe_table_id; - - nanouptime(&now); - timespecsub(&now, &swfe->swfe_installed_time, &duration); - ofr->fr_duration_sec = ntohl((int)duration.tv_sec); - ofr->fr_priority = htons(swfe->swfe_priority); - ofr->fr_idle_timeout = htons(swfe->swfe_idle_timeout); - ofr->fr_hard_timeout = htons(swfe->swfe_hard_timeout); - ofr->fr_byte_count = htobe64(swfe->swfe_byte_cnt); - ofr->fr_packet_count = htobe64(swfe->swfe_packet_cnt); - - memcpy(&ofr->fr_match, swfe->swfe_match, match_len); - - /* match_len inclusive ofp_match header length*/ - ofr->fr_oh.oh_length = - htons(sizeof(*ofr) + match_len - sizeof(struct ofp_match)); - - m->m_len = m->m_pkthdr.len = - sizeof(*ofr) + match_len - sizeof(struct ofp_match); - - return (swofp_output(sc, m)); -} - -/* - * OpenFlow protocol FLOW MOD message handlers - */ -int -swofp_flow_entry_put_instructions(struct switch_softc *sc, struct mbuf *m, - struct swofp_flow_entry *swfe, uint16_t *etype, uint16_t *error) -{ - struct ofp_flow_mod *ofm; - struct ofp_instruction *oi; - caddr_t inst; - int start, len, off; - - *etype = OFP_ERRTYPE_BAD_INSTRUCTION; - - ofm = mtod(m, struct ofp_flow_mod *); - - /* - * Clear instructions from flow entry. It's necessary to only modify - * flow but it's no problem to clear on adding flow because the flow - * entry doesn't have any instructions. So it's always called. - */ - swofp_flow_entry_instruction_free(swfe); - - start = OFP_FLOW_MOD_MSG_INSTRUCTION_OFFSET(ofm); - len = ntohs(ofm->fm_oh.oh_length) - start; - for (off = start; off < start + len; off += ntohs(oi->i_len)) { - oi = (struct ofp_instruction *)(mtod(m, caddr_t) + off); - - if (swofp_validate_flow_instruction(sc, oi, - len - (off - start), etype, error)) - return (-1); - - if ((inst = malloc(ntohs(oi->i_len), M_DEVBUF, - M_DONTWAIT|M_ZERO)) == NULL) { - *error = OFP_ERRFLOWMOD_UNKNOWN; - return (-1); - } - memcpy(inst, oi, ntohs(oi->i_len)); - - switch (ntohs(oi->i_type)) { - case OFP_INSTRUCTION_T_GOTO_TABLE: - if (swfe->swfe_goto_table) - free(swfe->swfe_goto_table, M_DEVBUF, - ntohs(swfe->swfe_goto_table->igt_len)); - - swfe->swfe_goto_table = - (struct ofp_instruction_goto_table *)inst; - break; - case OFP_INSTRUCTION_T_WRITE_META: - if (swfe->swfe_write_metadata) - free(swfe->swfe_write_metadata, M_DEVBUF, - ntohs(swfe->swfe_write_metadata->iwm_len)); - - swfe->swfe_write_metadata = - (struct ofp_instruction_write_metadata *)inst; - break; - case OFP_INSTRUCTION_T_WRITE_ACTIONS: - if (swfe->swfe_write_actions) - free(swfe->swfe_write_actions, M_DEVBUF, - ntohs(swfe->swfe_write_actions->ia_len)); - - swfe->swfe_write_actions = - (struct ofp_instruction_actions *)inst; - break; - case OFP_INSTRUCTION_T_APPLY_ACTIONS: - if (swfe->swfe_apply_actions) - free(swfe->swfe_apply_actions, M_DEVBUF, - ntohs(swfe->swfe_apply_actions->ia_len)); - - swfe->swfe_apply_actions = - (struct ofp_instruction_actions *)inst; - break; - case OFP_INSTRUCTION_T_CLEAR_ACTIONS: - if (swfe->swfe_clear_actions) - free(swfe->swfe_clear_actions, M_DEVBUF, - ntohs(swfe->swfe_clear_actions->ia_len)); - - swfe->swfe_clear_actions = - (struct ofp_instruction_actions *)inst; - break; - case OFP_INSTRUCTION_T_METER: - if (swfe->swfe_meter) - free(swfe->swfe_meter, M_DEVBUF, - ntohs(swfe->swfe_meter->im_len)); - - swfe->swfe_meter = (struct ofp_instruction_meter *)inst; - break; - case OFP_INSTRUCTION_T_EXPERIMENTER: - if (swfe->swfe_experimenter) - free(swfe->swfe_experimenter, M_DEVBUF, - ntohs(swfe->swfe_experimenter->ie_len)); - - swfe->swfe_experimenter = - (struct ofp_instruction_experimenter *)inst; - break; - default: - free(inst, M_DEVBUF, ntohs(oi->i_len)); - break; - } - } - - return (0); -} - -int -swofp_flow_mod_cmd_add(struct switch_softc *sc, struct mbuf *m) -{ - struct swofp_ofs *ofs = sc->sc_ofs; - struct ofp_flow_mod *ofm; - struct ofp_match *om; - struct swofp_flow_entry *swfe, *old_swfe; - struct swofp_flow_table *swft; - int omlen; - uint16_t error, etype; - - etype = OFP_ERRTYPE_FLOW_MOD_FAILED; - ofm = mtod(m, struct ofp_flow_mod *); - om = &ofm->fm_match; - - if (OFP_TABLE_ID_MAX < ofm->fm_table_id) { - error = OFP_ERRFLOWMOD_TABLE_ID; - goto ofp_error; - } - - if (ofm->fm_cookie == UINT64_MAX) { - /* XXX What is best error code? */ - error = OFP_ERRFLOWMOD_UNKNOWN; - goto ofp_error; - } - - omlen = ntohs(om->om_length); - /* - * 1) ofp_match header must have at least its own size, - * otherwise memcpy() will fail later; - * 2) OXM filters can't be bigger than the packet. - */ - if (omlen < sizeof(*om) || - omlen >= (m->m_len - sizeof(*ofm))) { - etype = OFP_ERRTYPE_BAD_MATCH; - error = OFP_ERRMATCH_BAD_LEN; - goto ofp_error; - } - - if ((swft = swofp_flow_table_add(sc, ofm->fm_table_id)) == NULL) { - error = OFP_ERRFLOWMOD_TABLE_ID; - goto ofp_error; - } - - if (swft->swft_flow_num >= ofs->swofs_flow_max_entry) { - error = OFP_ERRFLOWMOD_TABLE_FULL; - goto ofp_error; - } - - /* Validate that the OXM are in-place and correct. */ - if (swofp_validate_flow_match(om, &error)) { - etype = OFP_ERRTYPE_BAD_MATCH; - goto ofp_error; - } - - if ((old_swfe = swofp_flow_search_by_table(swft, om, - ntohs(ofm->fm_priority)))) { - if (ntohs(ofm->fm_flags) & OFP_FLOWFLAG_CHECK_OVERLAP) { - error = OFP_ERRFLOWMOD_OVERLAP; - goto ofp_error; - } - } - - if ((swfe = malloc(sizeof(*swfe), M_DEVBUF, - M_DONTWAIT|M_ZERO)) == NULL) { - error = OFP_ERRFLOWMOD_UNKNOWN; - goto ofp_error; - } - - swfe->swfe_priority = ntohs(ofm->fm_priority); - swfe->swfe_cookie = be64toh(ofm->fm_cookie); - swfe->swfe_flags = ntohs(ofm->fm_flags); - swfe->swfe_idle_timeout = ntohs(ofm->fm_idle_timeout); - swfe->swfe_hard_timeout = ntohs(ofm->fm_hard_timeout); - nanouptime(&swfe->swfe_installed_time); - nanouptime(&swfe->swfe_idle_time); - - if ((swfe->swfe_match = malloc(omlen, M_DEVBUF, - M_DONTWAIT|M_ZERO)) == NULL) { - error = OFP_ERRFLOWMOD_UNKNOWN; - goto ofp_error_free_flow; - } - memcpy(swfe->swfe_match, om, omlen); - - /* - * If the ofp_match structure is empty and priority is zero, then - * this is a special flow type called table-miss which is the last - * flow to match. - */ - if (omlen == sizeof(*om) && swfe->swfe_priority == 0) - swfe->swfe_tablemiss = 1; - - if (swofp_flow_entry_put_instructions(sc, m, swfe, &etype, &error)) - goto ofp_error_free_flow; - - if (old_swfe) { - if (!(ntohs(ofm->fm_flags) & OFP_FLOWFLAG_RESET_COUNTS)) { - swfe->swfe_packet_cnt = old_swfe->swfe_packet_cnt; - swfe->swfe_byte_cnt = old_swfe->swfe_byte_cnt; - } - /* - * Doesn't need to send flow remove message because - * this deleted flow cause by internal reason - */ - swfe->swfe_flags &= ~(OFP_FLOWFLAG_SEND_FLOW_REMOVED); - swofp_flow_entry_delete(sc, swft, old_swfe, - OFP_FLOWREM_REASON_DELETE); - } - - swofp_flow_entry_add(sc, swft, swfe); - - m_freem(m); - return (0); - - ofp_error_free_flow: - swofp_flow_entry_free(&swfe); - ofp_error: - swofp_send_error(sc, m, etype, error); - return (0); -} - -int -swofp_flow_mod_cmd_common_modify(struct switch_softc *sc, struct mbuf *m, - int strict) -{ - struct ofp_flow_mod *ofm; - struct ofp_match *om; - struct swofp_flow_entry *swfe; - struct swofp_flow_table *swft; - int omlen; - uint16_t error, etype; - - etype = OFP_ERRTYPE_FLOW_MOD_FAILED; - - ofm = mtod(m, struct ofp_flow_mod *); - om = &ofm->fm_match; - - if (OFP_TABLE_ID_MAX < ofm->fm_table_id) { - error = OFP_ERRFLOWMOD_TABLE_ID; - goto ofp_error; - } - - if (ofm->fm_cookie == UINT64_MAX) { - /* XXX What is best error code? */ - error = OFP_ERRFLOWMOD_UNKNOWN; - goto ofp_error; - } - - omlen = ntohs(om->om_length); - /* - * 1) ofp_match header must have at least its own size, - * otherwise memcpy() will fail later; - * 2) OXM filters can't be bigger than the packet. - */ - if (omlen < sizeof(*om) || - omlen >= (m->m_len - sizeof(*ofm))) { - etype = OFP_ERRTYPE_BAD_MATCH; - error = OFP_ERRMATCH_BAD_LEN; - goto ofp_error; - } - - /* Validate that the OXM are in-place and correct. */ - if (swofp_validate_flow_match(om, &error)) { - etype = OFP_ERRTYPE_BAD_MATCH; - goto ofp_error; - } - - if ((swft = swofp_flow_table_lookup(sc, ofm->fm_table_id)) == NULL) { - error = OFP_ERRFLOWMOD_TABLE_ID; - goto ofp_error; - } - - LIST_FOREACH(swfe, &swft->swft_flow_list, swfe_next) { - if (strict && !swofp_flow_cmp_strict(swfe, om, - ntohs(ofm->fm_priority))) - continue; - else if (!swofp_flow_cmp_non_strict(swfe, om)) - continue; - - if (!swofp_flow_filter(swfe, be64toh(ofm->fm_cookie), - be64toh(ofm->fm_cookie_mask), ntohl(ofm->fm_out_port), - ntohl(ofm->fm_out_group))) - continue; - - if (swofp_flow_entry_put_instructions(sc, m, swfe, &etype, - &error)) { - /* - * If error occurs in swofp_flow_entry_put_instructions, - * the flow entry might be half-way modified. So the - * flow entry is delete here. - */ - swofp_flow_entry_delete(sc, swft, swfe, - OFP_FLOWREM_REASON_DELETE); - etype = OFP_ERRTYPE_BAD_INSTRUCTION; - goto ofp_error; - } - - if (ntohs(ofm->fm_flags) & OFP_FLOWFLAG_RESET_COUNTS) { - swfe->swfe_packet_cnt = 0; - swfe->swfe_byte_cnt = 0; - } - } - - m_freem(m); - return (0); - - ofp_error: - swofp_send_error(sc, m, etype, error); - return (0); -} - -int -swofp_flow_mod_cmd_modify(struct switch_softc *sc, struct mbuf *m) -{ - return swofp_flow_mod_cmd_common_modify(sc, m, 0); -} - -int -swofp_flow_mod_cmd_modify_strict(struct switch_softc *sc, struct mbuf *m) -{ - return swofp_flow_mod_cmd_common_modify(sc, m, 1); -} - - -int -swofp_flow_mod_cmd_common_delete(struct switch_softc *sc, struct mbuf *m, - int strict) -{ - struct swofp_ofs *ofs = sc->sc_ofs; - struct ofp_flow_mod *ofm; - struct ofp_match *om; - struct swofp_flow_table *swft; - int omlen; - uint16_t error, etype = OFP_ERRTYPE_FLOW_MOD_FAILED; - - ofm = (struct ofp_flow_mod *)(mtod(m, caddr_t)); - om = &ofm->fm_match; - - omlen = ntohs(om->om_length); - /* - * 1) ofp_match header must have at least its own size, - * otherwise memcpy() will fail later; - * 2) OXM filters can't be bigger than the packet. - */ - if (omlen < sizeof(*om) || - omlen >= (m->m_len - sizeof(*ofm))) { - etype = OFP_ERRTYPE_BAD_MATCH; - error = OFP_ERRMATCH_BAD_LEN; - goto ofp_error; - } - - /* Validate that the OXM are in-place and correct. */ - if (swofp_validate_flow_match(om, &error)) { - etype = OFP_ERRTYPE_BAD_MATCH; - goto ofp_error; - } - - TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) { - if ((ofm->fm_table_id != OFP_TABLE_ID_ALL) && - (ofm->fm_table_id != swft->swft_table_id)) - continue; - - swofp_flow_delete_on_table(sc, swft, om, - ntohs(ofm->fm_priority), - be64toh(ofm->fm_cookie), - be64toh(ofm->fm_cookie_mask), - ntohl(ofm->fm_out_port), - ntohl(ofm->fm_out_group), strict); - } - - m_freem(m); - return (0); - - ofp_error: - swofp_send_error(sc, m, etype, error); - return (-1); -} - -int -swofp_flow_mod_cmd_delete(struct switch_softc *sc, struct mbuf *m) -{ - return swofp_flow_mod_cmd_common_delete(sc, m, 0); -} - -int -swofp_flow_mod_cmd_delete_strict(struct switch_softc *sc, struct mbuf *m) -{ - return swofp_flow_mod_cmd_common_delete(sc, m, 1); -} - -ofp_msg_handler * -swofp_flow_mod_lookup_handler(uint8_t cmd) -{ - if (cmd >= nitems(ofp_flow_mod_table)) - return (NULL); - else - return (&ofp_flow_mod_table[cmd].ofm_cmd_handler); -} - -int -swofp_flow_mod(struct switch_softc *sc, struct mbuf *m) -{ - struct ofp_flow_mod *ofm; - ofp_msg_handler *handler; - uint16_t ohlen; - - ofm = mtod(m, struct ofp_flow_mod *); - ohlen = ntohs(ofm->fm_oh.oh_length); - if (ohlen < sizeof(*ofm) || - ohlen < (sizeof(*ofm) + ntohs(ofm->fm_match.om_length))) { - swofp_send_error(sc, m, OFP_ERRTYPE_BAD_REQUEST, - OFP_ERRREQ_BAD_LEN); - return (-1); - } - - handler = swofp_flow_mod_lookup_handler(ofm->fm_command); - if (handler) { - (*handler)(sc, m); - } else { - swofp_send_error(sc, m, OFP_ERRTYPE_FLOW_MOD_FAILED, - OFP_ERRFLOWMOD_BAD_COMMAND); - } - - return (0); -} - -int -swofp_group_mod_add(struct switch_softc *sc, struct mbuf *m) -{ - struct swofp_ofs *ofs = sc->sc_ofs; - struct ofp_group_mod *ogm; - struct swofp_group_entry *swge; - uint16_t error, etype; - - etype = OFP_ERRTYPE_GROUP_MOD_FAILED; - ogm = mtod(m, struct ofp_group_mod *); - - if (ofs->swofs_group_table_num >= ofs->swofs_group_max_table) { - error = OFP_ERRGROUPMOD_OUT_OF_GROUPS; - goto failed; - } - - if (ntohl(ogm->gm_group_id) > OFP_GROUP_ID_MAX) { - error = OFP_ERRGROUPMOD_INVALID_GROUP; - goto failed; - } - - if ((swge = swofp_group_entry_lookup(sc, - ntohl(ogm->gm_group_id)))) { - error = OFP_ERRGROUPMOD_GROUP_EXISTS; - goto failed; - } - - if (ogm->gm_type != OFP_GROUP_T_ALL) { - /* support ALL group only now*/ - error = OFP_ERRGROUPMOD_BAD_TYPE; - goto failed; - } - - if (swofp_validate_buckets(sc, m, ogm->gm_type, &etype, &error)) - goto failed; - - if ((swge = malloc(sizeof(*swge), M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) { - error = OFP_ERRGROUPMOD_UNKNOWN_GROUP; - goto failed; - } - - swge->swge_group_id = ntohl(ogm->gm_group_id); - swge->swge_type = ogm->gm_type; - - swge->swge_buckets_len = (ntohs(ogm->gm_oh.oh_length) - - offsetof(struct ofp_group_mod, gm_buckets)); - - if (swge->swge_buckets_len > 0) { - if ((swge->swge_buckets = malloc(swge->swge_buckets_len, - M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) { - free(swge, M_DEVBUF, sizeof(*swge)); - error = OFP_ERRGROUPMOD_UNKNOWN_GROUP; - goto failed; - } - - m_copydata(m, offsetof(struct ofp_group_mod, gm_buckets), - swge->swge_buckets_len, swge->swge_buckets); - } - - swofp_group_entry_add(sc, swge); - - m_freem(m); - return (0); - - failed: - swofp_send_error(sc, m, etype, error); - return (0); -} - -int -swofp_group_mod_modify(struct switch_softc *sc, struct mbuf *m) -{ - struct ofp_group_mod *ogm; - struct swofp_group_entry *swge; - uint16_t error, etype; - uint32_t obucketlen; - - etype = OFP_ERRTYPE_GROUP_MOD_FAILED; - ogm = mtod(m, struct ofp_group_mod *); - - if (ogm->gm_type != OFP_GROUP_T_ALL) { - /* support ALL group only now */ - error = OFP_ERRGROUPMOD_BAD_TYPE; - goto failed; - } - - if ((swge = swofp_group_entry_lookup(sc, - ntohl(ogm->gm_group_id))) == NULL) { - error = OFP_ERRGROUPMOD_UNKNOWN_GROUP; - goto failed; - } - - if (swofp_validate_buckets(sc, m, ogm->gm_type, &etype, &error)) - goto failed; - - swge->swge_type = ogm->gm_type; - - obucketlen = swge->swge_buckets_len; - swge->swge_buckets_len = (ntohs(ogm->gm_oh.oh_length) - - offsetof(struct ofp_group_mod, gm_buckets)); - - if (obucketlen != swge->swge_buckets_len) { - free(swge->swge_buckets, M_DEVBUF, obucketlen); - swge->swge_buckets = NULL; - - if (swge->swge_buckets_len > 0 && - (swge->swge_buckets = malloc(swge->swge_buckets_len, - M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) { - free(swge, M_DEVBUF, sizeof(*swge)); - error = OFP_ERRGROUPMOD_UNKNOWN_GROUP; - goto failed; - } - } - - if (swge->swge_buckets != NULL) - m_copydata(m, offsetof(struct ofp_group_mod, gm_buckets), - swge->swge_buckets_len, swge->swge_buckets); - - m_freem(m); - return (0); -failed: - swofp_send_error(sc, m, etype, error); - return (0); -} - -int -swofp_group_mod_delete(struct switch_softc *sc, struct mbuf *m) -{ - struct ofp_group_mod *ogm; - struct swofp_group_entry *swge; - int group_id; - - ogm = mtod(m, struct ofp_group_mod *); - group_id = ntohl(ogm->gm_group_id); - - if (group_id == OFP_GROUP_ID_ALL) - swofp_group_entry_delete_all(sc); - else if ((swge = swofp_group_entry_lookup(sc, group_id)) != NULL) - swofp_group_entry_delete(sc, swge); - else { - swofp_send_error(sc, m, OFP_ERRTYPE_GROUP_MOD_FAILED, - OFP_ERRGROUPMOD_UNKNOWN_GROUP); - return (0); - } - - m_freem(m); - return (0); -} - -int -swofp_group_mod(struct switch_softc *sc, struct mbuf *m) -{ - struct ofp_group_mod *ogm; - uint16_t cmd; - - ogm = mtod(m, struct ofp_group_mod *); - if (ntohs(ogm->gm_oh.oh_length) < sizeof(*ogm)) { - swofp_send_error(sc, m, OFP_ERRTYPE_BAD_REQUEST, - OFP_ERRREQ_BAD_LEN); - return (-1); - } - - cmd = ntohs(ogm->gm_command); - - switch (cmd) { - case OFP_GROUPCMD_ADD: - return swofp_group_mod_add(sc, m); - case OFP_GROUPCMD_MODIFY: - return swofp_group_mod_modify(sc, m); - case OFP_GROUPCMD_DELETE: - return swofp_group_mod_delete(sc, m); - default: - swofp_send_error(sc, m, OFP_ERRTYPE_GROUP_MOD_FAILED, - OFP_ERRGROUPMOD_BAD_COMMAND); - break; - } - - return (0); -} - - - -/* - * OpenFlow protocol PACKET OUT message handler - */ -int -swofp_recv_packet_out(struct switch_softc *sc, struct mbuf *m) -{ - struct ofp_packet_out *pout; - struct ofp_action_header *ah; - struct mbuf *mc = NULL, *mcn; - int al_start, al_len, off; - uint16_t ohlen, error; - struct switch_flow_classify swfcl = {}; - struct swofp_pipeline_desc swpld = { .swpld_swfcl = &swfcl }; - - pout = mtod(m, struct ofp_packet_out *); - ohlen = ntohs(pout->pout_oh.oh_length); - if (ohlen < sizeof(*pout) || - ohlen < (sizeof(*pout) + ntohs(pout->pout_actions_len))) { - swofp_send_error(sc, m, OFP_ERRTYPE_BAD_REQUEST, - OFP_ERRREQ_BAD_LEN); - return (-1); - } - - al_len = ntohs(pout->pout_actions_len); - al_start = offsetof(struct ofp_packet_out, pout_actions); - - /* Validate actions before anything else. */ - ah = (struct ofp_action_header *) - ((uint8_t *)pout + sizeof(*pout)); - if (swofp_validate_action(sc, ah, al_len, &error)) { - swofp_send_error(sc, m, OFP_ERRTYPE_BAD_ACTION, error); - return (EINVAL); - } - - if (pout->pout_buffer_id == OFP_PKTOUT_NO_BUFFER) { - /* - * It's not necessary to deep copy at here because it's done - * in m_dup_pkt(). - */ - if ((mc = m_split(m, (al_start + al_len), M_NOWAIT)) == NULL) { - m_freem(m); - return (ENOBUFS); - } - - mcn = m_dup_pkt(mc, ETHER_ALIGN, M_NOWAIT); - m_freem(mc); - if (mcn == NULL) { - m_freem(m); - return (ENOBUFS); - } - - mc = mcn; - } else { - /* TODO We don't do buffering yet. */ - swofp_send_error(sc, m, OFP_ERRTYPE_BAD_REQUEST, - OFP_ERRREQ_BUFFER_UNKNOWN); - return (0); - } - - mc = switch_flow_classifier(mc, pout->pout_in_port, &swfcl); - if (mc == NULL) { - m_freem(m); - return (0); - } - - TAILQ_INIT(&swpld.swpld_fwdp_q); - swfcl.swfcl_in_port = ntohl(pout->pout_in_port); - for (off = al_start; off < al_start + al_len; - off += ntohs(ah->ah_len)) { - ah = (struct ofp_action_header *)(mtod(m, caddr_t) + off); - - mc = swofp_execute_action(sc, mc, &swpld, ah); - if (mc == NULL) - break; - } - - if (mc) - switch_port_egress(sc, &swpld.swpld_fwdp_q, mc); - - m_freem(m); - - return (0); -} - -/* - * OpenFlow protocol MULTIPART message: - * - * Multipart messages are used to carry a large amount of data because a single - * OpenFlow message is limited to 64KB. If a message is over 64KB, it is - * splited some OpenFlow messages. OpenFlow Switch Specification says that - * "NO OBJECT CAN BE SPLIT ACROSS TWO MESSAGES". In other words, point of - * splittig is different per reply, so switch(4) builds multipart message using - * swofp_mpms_* functions which splits messages not to object across - * two messages. - */ -int -swofp_mpmsg_reply_create(struct ofp_multipart *req, struct swofp_mpmsg *swmp) -{ - struct mbuf *hdr, *body; - struct ofp_multipart *omp; - - memset(swmp, 0, sizeof(*swmp)); - - ml_init(&swmp->swmp_body); - - MGETHDR(hdr, M_DONTWAIT, MT_DATA); - if (hdr == NULL) - goto error; - - memset(mtod(hdr, caddr_t), 0, sizeof(*omp)); - omp = mtod(hdr, struct ofp_multipart *); - omp->mp_oh.oh_version = req->mp_oh.oh_version; - omp->mp_oh.oh_xid = req->mp_oh.oh_xid; - omp->mp_oh.oh_type = OFP_T_MULTIPART_REPLY; - omp->mp_type = req->mp_type; - hdr->m_len = hdr->m_pkthdr.len = sizeof(*omp); - swmp->swmp_hdr = hdr; - - MGETHDR(body, M_DONTWAIT, MT_DATA); - if (body == NULL) - goto error; - MCLGET(body, M_DONTWAIT); - if ((body->m_flags & M_EXT) == 0) { - m_freem(body); - goto error; - } - body->m_len = body->m_pkthdr.len = 0; - - ml_enqueue(&swmp->swmp_body, body); - - return (0); - - error: - m_freem(hdr); - swmp->swmp_hdr = NULL; - return (ENOBUFS); -} - -/* - * Copy data from a buffer back into the indicated swmp's body buffer - */ -int -swofp_mpmsg_put(struct swofp_mpmsg *swmp, caddr_t data, size_t len) -{ - struct mbuf *m, *n; - int error; - - KASSERT(swmp->swmp_hdr != NULL); - - m = swmp->swmp_body.ml_tail; - if (m == NULL) - return (ENOBUFS); - - if (m->m_pkthdr.len + len > SWOFP_MPMSG_MAX) { - MGETHDR(n, M_DONTWAIT, MT_DATA); - if (n == NULL) - return (ENOBUFS); - MCLGET(n, M_DONTWAIT); - if ((n->m_flags & M_EXT) == 0) { - m_freem(n); - return (ENOBUFS); - } - n->m_len = n->m_pkthdr.len = 0; - - ml_enqueue(&swmp->swmp_body, n); - - m = n; - } - - if ((error = m_copyback(m, m->m_pkthdr.len, len, data, M_NOWAIT))) - return (error); - - return (0); -} - -/* - * Copy data from a mbuf back into the indicated swmp's body buffer - */ -int -swofp_mpmsg_m_put(struct swofp_mpmsg *swmp, struct mbuf *msg) -{ - struct mbuf *m, *n; - int len; - - KASSERT(swmp->swmp_hdr != NULL); - - m = swmp->swmp_body.ml_tail; - if (m == NULL) - return (ENOBUFS); - - if (m->m_pkthdr.len + msg->m_pkthdr.len > SWOFP_MPMSG_MAX) { - MGETHDR(n, M_DONTWAIT, MT_DATA); - if (n == NULL) - return (ENOBUFS); - MCLGET(n, M_DONTWAIT); - if ((n->m_flags & M_EXT) == 0) { - m_freem(n); - return (ENOBUFS); - } - n->m_len = n->m_pkthdr.len = 0; - - ml_enqueue(&swmp->swmp_body, n); - - m = n; - } - - len = m->m_pkthdr.len + msg->m_pkthdr.len; - m_cat(m, msg); - m->m_pkthdr.len = len; - - return (0); -} - -void -swofp_mpmsg_destroy(struct swofp_mpmsg *swmp) -{ - m_freem(swmp->swmp_hdr); - ml_purge(&swmp->swmp_body); -} - -int -swofp_multipart_req(struct switch_softc *sc, struct mbuf *m) -{ - struct ofp_multipart *omp; - ofp_msg_handler handler; - - omp = mtod(m, struct ofp_multipart *); - if (ntohs(omp->mp_oh.oh_length) < sizeof(*omp)) { - swofp_send_error(sc, m, OFP_ERRTYPE_BAD_REQUEST, - OFP_ERRREQ_BAD_LEN); - return (-1); - } - - if (omp->mp_flags & OFP_T_MULTIPART_REQUEST) { - /* multipart message re-assembly iss not supported yet */ - m_freem(m); - return (ENOBUFS); - } - - handler = swofp_lookup_mpmsg_handler(ntohs(omp->mp_type)); - if (handler) - (*handler)(sc, m); - else - swofp_send_error(sc, m, OFP_ERRTYPE_BAD_REQUEST, - OFP_ERRREQ_MULTIPART); - - return (0); -} - -int -swofp_multipart_reply(struct switch_softc *sc, struct swofp_mpmsg *swmp) -{ - struct ofp_multipart *omp; - struct mbuf *hdr, *body; - int len, error = 0; - - KASSERT(swmp->swmp_hdr != NULL); - - omp = mtod(swmp->swmp_hdr, struct ofp_multipart *); - - while ((body = ml_dequeue(&swmp->swmp_body)) != NULL) { - omp->mp_oh.oh_length = htons(sizeof(*omp) + body->m_pkthdr.len); - - if (swmp->swmp_body.ml_tail != NULL) { - omp->mp_flags |= htons(OFP_MP_FLAG_REPLY_MORE); - if ((hdr = m_dup_pkt(swmp->swmp_hdr, 0, - M_WAITOK)) == NULL) { - error = ENOBUFS; - goto error; - } - } else { - omp->mp_flags &= ~htons(OFP_MP_FLAG_REPLY_MORE); - hdr = swmp->swmp_hdr; - } - - if (body->m_pkthdr.len) { - len = hdr->m_pkthdr.len + body->m_pkthdr.len; - m_cat(hdr, body); - hdr->m_pkthdr.len = len; - } else - m_freem(body); - - (void)swofp_output(sc, hdr); - } - - return (0); - error: - swofp_mpmsg_destroy(swmp); - return (error); -} - -int -swofp_put_flow(struct mbuf *m, struct swofp_flow_table *swft, - struct swofp_flow_entry *swfe) -{ - struct ofp_flow_stats *pofs, ofs; - struct timespec now, duration; - const uint8_t pad_data[OFP_ALIGNMENT] = {}; - struct mbuf *n; - int start, off, error, offp, pad = 0; - int omlen; - - memset(&ofs, 0, sizeof(ofs)); - - ofs.fs_table_id = swft->swft_table_id; - nanouptime(&now); - timespecsub(&now, &swfe->swfe_installed_time, &duration); - ofs.fs_duration_sec = ntohl((int)duration.tv_sec); - ofs.fs_priority = htons(swfe->swfe_priority); - ofs.fs_idle_timeout = htons(swfe->swfe_idle_timeout); - ofs.fs_hard_timeout = htons(swfe->swfe_hard_timeout); - ofs.fs_cookie = htobe64(swfe->swfe_cookie); - ofs.fs_byte_count = htobe64(swfe->swfe_byte_cnt); - ofs.fs_packet_count = htobe64(swfe->swfe_packet_cnt); - - /* - * struct ofp_flow_statsu has some fields which is variable length , - * so the length is determined by all fields puts. - */ - start = off = m->m_pkthdr.len; - - /* - * Put ofp_flow_stat exclusive ofp_match because ofp_match is put - * with ofp_matches - */ - if ((error = m_copyback(m, off, (sizeof(ofs) - - sizeof(struct ofp_match)), &ofs, M_NOWAIT))) - goto failed; - off += (sizeof(ofs) - sizeof(struct ofp_match)); - - /* - * Put ofp_match include ofp_ox_matches and pad - */ - omlen = ntohs(swfe->swfe_match->om_length); - pad = OFP_ALIGN(omlen) - omlen; - if ((error = m_copyback(m, off, omlen, swfe->swfe_match, M_NOWAIT))) - goto failed; - off += omlen; - if ((error = m_copyback(m, off, pad, pad_data, M_NOWAIT))) - goto failed; - off += pad; - - /* - * Put instructions - */ - if (swfe->swfe_goto_table) { - if ((error = m_copyback(m, off, - ntohs(swfe->swfe_goto_table->igt_len), - swfe->swfe_goto_table, M_NOWAIT))) - goto failed; - off += ntohs(swfe->swfe_goto_table->igt_len); - } - if (swfe->swfe_write_metadata) { - if ((error = m_copyback(m, off, - ntohs(swfe->swfe_write_metadata->iwm_len), - swfe->swfe_write_metadata, M_NOWAIT))) - goto failed; - off += ntohs(swfe->swfe_write_metadata->iwm_len); - } - if (swfe->swfe_apply_actions) { - if ((error = m_copyback(m, off, - ntohs(swfe->swfe_apply_actions->ia_len), - swfe->swfe_apply_actions, M_NOWAIT))) - goto failed; - off += ntohs(swfe->swfe_apply_actions->ia_len); - } - if (swfe->swfe_write_actions) { - if ((error = m_copyback(m, off, - ntohs(swfe->swfe_write_actions->ia_len), - swfe->swfe_write_actions, M_NOWAIT))) - goto failed; - off += ntohs(swfe->swfe_write_actions->ia_len); - } - if (swfe->swfe_clear_actions) { - if ((error = m_copyback(m, off, - ntohs(swfe->swfe_clear_actions->ia_len), - swfe->swfe_clear_actions, M_NOWAIT))) - goto failed; - off += ntohs(swfe->swfe_clear_actions->ia_len); - } - - /* - * Set ofp_flow_stat length - */ - if ((n = m_pulldown(m, start, sizeof(*pofs), &offp)) == NULL) - return (ENOBUFS); - pofs = (struct ofp_flow_stats *)(mtod(n, caddr_t) + offp); - pofs->fs_length = htons(off - start); - - return (0); - - failed: - m_freem(m); - return (error); -} - -int -swofp_mp_recv_desc(struct switch_softc *sc, struct mbuf *m) -{ - struct ofp_desc od; - struct swofp_mpmsg swmp; - int error; - - if ((error = swofp_mpmsg_reply_create( - mtod(m, struct ofp_multipart *), &swmp))) - goto failed; - - memset(&od, 0, sizeof(od)); - - strlcpy(od.d_mfr_desc, "openbsd.org", OFP_DESC_STR_LEN); - strlcpy(od.d_hw_desc, "openbsd", OFP_DESC_STR_LEN); - strlcpy(od.d_sw_desc, "openbsd", OFP_DESC_STR_LEN); - strlcpy(od.d_serial_num, "0", OFP_SERIAL_NUM_LEN); - strlcpy(od.d_dp_desc, sc->sc_if.if_xname, OFP_DESC_STR_LEN); - - if ((error = swofp_mpmsg_put(&swmp, (caddr_t)&od, sizeof(od)))) - goto failed; - - m_freem(m); - return swofp_multipart_reply(sc, &swmp); - - failed: - m_freem(m); - swofp_mpmsg_destroy(&swmp); - return (error); -} - -int -swofp_put_flows_from_table(struct swofp_mpmsg *swmp, - struct swofp_flow_table *swft, struct ofp_flow_stats_request *ofsr) -{ - struct swofp_flow_entry *swfe; - struct mbuf *m; - int error = 0; - - LIST_FOREACH(swfe, &swft->swft_flow_list, swfe_next) { - if (!swofp_flow_cmp_non_strict(swfe, &ofsr->fsr_match)) - continue; - - if (!swofp_flow_filter(swfe, be64toh(ofsr->fsr_cookie), - be64toh(ofsr->fsr_cookie_mask), ntohl(ofsr->fsr_out_port), - ntohl(ofsr->fsr_out_group))) - continue; - - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) - return (ENOBUFS); - m->m_len = m->m_pkthdr.len = 0; - - if ((error = swofp_put_flow(m, swft, swfe))) - break; - - if ((error = swofp_mpmsg_m_put(swmp, m))) { - /* swofp_mpmsg_m_put() doesn't free m on error */ - m_freem(m); - break; - } - } - - return (error); -} - -int -swofp_mp_recv_flow(struct switch_softc *sc, struct mbuf *m) -{ - struct swofp_ofs *ofs = sc->sc_ofs; - struct ofp_flow_stats_request *ofsr; - struct swofp_flow_table *swft; - struct swofp_mpmsg swmp; - int error; - - if ((error = swofp_mpmsg_reply_create( - mtod(m, struct ofp_multipart *), &swmp))) - goto failed; - - ofsr = (struct ofp_flow_stats_request *) - (mtod(m, caddr_t) + sizeof(struct ofp_multipart)); - - TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) { - if ((ofsr->fsr_table_id != OFP_TABLE_ID_ALL) && - (ofsr->fsr_table_id != swft->swft_table_id)) - continue; - - if ((error = swofp_put_flows_from_table(&swmp, swft, ofsr))) - goto failed; - } - - m_freem(m); - return swofp_multipart_reply(sc, &swmp); - - failed: - m_freem(m); - swofp_mpmsg_destroy(&swmp); - return (error); -} - -void -swofp_aggregate_stat_from_table(struct ofp_aggregate_stats *aggstat, - struct swofp_flow_table *swft, struct ofp_aggregate_stats_request *oasr) -{ - struct swofp_flow_entry *swfe; - uint64_t packet_cnt = 0, byte_cnt = 0; - uint32_t flow_cnt = 0; - - LIST_FOREACH(swfe, &swft->swft_flow_list, swfe_next) { - if (!swofp_flow_cmp_non_strict(swfe, &oasr->asr_match)) - continue; - - if (!swofp_flow_filter(swfe, be64toh(oasr->asr_cookie), - be64toh(oasr->asr_cookie_mask), ntohl(oasr->asr_out_port), - ntohl(oasr->asr_out_group))) - continue; - - packet_cnt += swfe->swfe_packet_cnt; - byte_cnt += swfe->swfe_byte_cnt; - flow_cnt++; - } - - aggstat->as_packet_count = htobe64(packet_cnt); - aggstat->as_byte_count = htobe64(byte_cnt); - aggstat->as_flow_count = htonl(flow_cnt++); -} - -int -swofp_mp_recv_aggregate_flow_stat(struct switch_softc *sc, struct mbuf *m) -{ - struct swofp_ofs *ofs = sc->sc_ofs; - struct ofp_aggregate_stats_request *oasr; - struct swofp_flow_table *swft; - struct swofp_mpmsg swmp; - struct ofp_aggregate_stats aggstat; - int error; - - if ((error = swofp_mpmsg_reply_create( - mtod(m, struct ofp_multipart *), &swmp))) - goto failed; - - memset(&aggstat, 0, sizeof(aggstat)); - - oasr = (struct ofp_aggregate_stats_request *) - (mtod(m, caddr_t) + sizeof(struct ofp_multipart)); - - TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) { - if ((oasr->asr_table_id != OFP_TABLE_ID_ALL) && - (oasr->asr_table_id != swft->swft_table_id)) - continue; - swofp_aggregate_stat_from_table(&aggstat, swft, oasr); - } - - if ((error = swofp_mpmsg_put(&swmp, (caddr_t)&aggstat, - sizeof(aggstat)))) - goto failed; - - m_freem(m); - return swofp_multipart_reply(sc, &swmp); - - failed: - m_freem(m); - swofp_mpmsg_destroy(&swmp); - return (error); -} - -int -swofp_mp_recv_table_stats(struct switch_softc *sc, struct mbuf *m) -{ - struct swofp_ofs *ofs = sc->sc_ofs; - struct ofp_table_stats tblstat; - struct swofp_flow_table *swft; - struct swofp_mpmsg swmp; - int error; - - - if ((error = swofp_mpmsg_reply_create( - mtod(m, struct ofp_multipart *), &swmp))) - goto failed; - - TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) { - memset(&tblstat, 0, sizeof(tblstat)); - - tblstat.ts_table_id = swft->swft_table_id; - tblstat.ts_active_count = htonl((uint32_t)swft->swft_flow_num); - tblstat.ts_lookup_count = htobe64(swft->swft_lookup_count); - tblstat.ts_matched_count = htobe64(swft->swft_matched_count); - - if ((error = swofp_mpmsg_put(&swmp, (caddr_t)&tblstat, - sizeof(tblstat)))) - goto failed; - } - - m_freem(m); - return swofp_multipart_reply(sc, &swmp); - - failed: - m_freem(m); - swofp_mpmsg_destroy(&swmp); - return (error); -} - -int -swofp_mp_recv_port_stats(struct switch_softc *sc, struct mbuf *m) -{ - struct switch_port *swpo; - struct swofp_mpmsg swmp; - struct ifnet *ifs; - struct ofp_port_stats postat; - int error; - struct timespec now, duration; - - if ((error = swofp_mpmsg_reply_create( - mtod(m, struct ofp_multipart *), &swmp))) - goto failed; - - nanouptime(&now); - - TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) { - memset(&postat, 0, sizeof(postat)); - ifs = if_get(swpo->swpo_ifindex); - if (ifs == NULL) - continue; - - 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); - postat.pt_tx_bytes = htobe64(ifs->if_ibytes); - postat.pt_rx_dropped = htobe64(ifs->if_iqdrops); - postat.pt_tx_dropped = htobe64(ifs->if_oqdrops); - postat.pt_rx_errors = htobe64(ifs->if_ierrors); - postat.pt_tx_errors = htobe64(ifs->if_oerrors); - postat.pt_rx_frame_err = htobe64(0); - postat.pt_rx_over_err = htobe64(0); - postat.pt_rx_crc_err = htobe64(0); - postat.pt_collision = htobe64(ifs->if_collisions); - timespecsub(&now, &swpo->swpo_appended, &duration); - postat.pt_duration_sec = htonl((uint32_t)duration.tv_sec); - postat.pt_duration_nsec = htonl(duration.tv_nsec); - - if_put(ifs); - - if ((error = swofp_mpmsg_put(&swmp, (caddr_t)&postat, - sizeof(postat)))) - goto failed; - } - - m_freem(m); - return swofp_multipart_reply(sc, &swmp); - - failed: - m_freem(m); - swofp_mpmsg_destroy(&swmp); - return (error); -} - -int -swofp_table_features_put_oxm(struct mbuf *m, int *off, uint16_t tp_type) -{ - struct ofp_table_feature_property tp; - struct ofp_ox_match oxm; - uint32_t padding = 0; - int i, supported = 0; - - for (i = 0 ; i < nitems(ofp_oxm_handlers); i++) { - switch (tp_type) { - case OFP_TABLE_FEATPROP_MATCH: - if (ofp_oxm_handlers[i].oxm_match == NULL) - continue; - break; - case OFP_TABLE_FEATPROP_WILDCARDS: - if (ofp_oxm_handlers[i].oxm_match == NULL || - !(ofp_oxm_handlers[i].oxm_flags & - SWOFP_MATCH_WILDCARD)) - continue; - break; - case OFP_TABLE_FEATPROP_APPLY_SETFIELD: - case OFP_TABLE_FEATPROP_APPLY_SETFIELD_MISS: - case OFP_TABLE_FEATPROP_WRITE_SETFIELD: - case OFP_TABLE_FEATPROP_WRITE_SETFIELD_MISS: - if (ofp_oxm_handlers[i].oxm_set == NULL) - continue; - break; - } - supported++; - } - - tp.tp_type = htons(tp_type); - tp.tp_length = htons((sizeof(oxm) * supported) + sizeof(tp)); - - if (m_copyback(m, *off, sizeof(tp), (caddr_t)&tp, M_NOWAIT)) - return (OFP_ERRREQ_MULTIPART_OVERFLOW); - *off += sizeof(tp); - - for (i = 0 ; i < nitems(ofp_oxm_handlers); i++) { - switch (tp_type) { - case OFP_TABLE_FEATPROP_MATCH: - if (ofp_oxm_handlers[i].oxm_match == NULL) - continue; - break; - case OFP_TABLE_FEATPROP_WILDCARDS: - if (ofp_oxm_handlers[i].oxm_match == NULL || - !(ofp_oxm_handlers[i].oxm_flags & - SWOFP_MATCH_WILDCARD)) - continue; - break; - case OFP_TABLE_FEATPROP_APPLY_SETFIELD: - case OFP_TABLE_FEATPROP_APPLY_SETFIELD_MISS: - case OFP_TABLE_FEATPROP_WRITE_SETFIELD: - case OFP_TABLE_FEATPROP_WRITE_SETFIELD_MISS: - if (ofp_oxm_handlers[i].oxm_set == NULL) - continue; - break; - } - - memset(&oxm, 0, sizeof(oxm)); - OFP_OXM_SET_FIELD(&oxm, ofp_oxm_handlers[i].oxm_field); - if ((tp_type == OFP_TABLE_FEATPROP_MATCH) && - (ofp_oxm_handlers[i].oxm_flags & SWOFP_MATCH_MASK)) - OFP_OXM_SET_HASMASK(&oxm); - oxm.oxm_class = htons(OFP_OXM_C_OPENFLOW_BASIC); - oxm.oxm_length = ofp_oxm_handlers[i].oxm_len; - - if (m_copyback(m, *off, sizeof(oxm), (caddr_t)&oxm, M_NOWAIT)) - return (OFP_ERRREQ_MULTIPART_OVERFLOW); - *off += sizeof(oxm); - } - - /* - * It's always 4 byte for padding because struct ofp_ox_mach and - * struct ofp_table_feature_property are 4 byte. - */ - if ((supported & 0x1) == 0) { - if (m_copyback(m, *off, sizeof(padding), - (caddr_t)&padding, M_NOWAIT)) - return (OFP_ERRREQ_MULTIPART_OVERFLOW); - *off += sizeof(padding); - } - - return (0); -} - -int -swofp_table_features_put_actions(struct mbuf *m, int *off, uint16_t tp_type) -{ - struct ofp_table_feature_property tp; - struct ofp_action_header action; - int i, supported = 0; - int actionlen, padsize; - uint8_t padding[8]; - - for (i = 0 ; i < nitems(ofp_action_handlers); i++) { - if (ofp_action_handlers[i].action) - supported++; - } - - actionlen = sizeof(action) - sizeof(action.ah_pad); - tp.tp_type = htons(tp_type); - tp.tp_length = (actionlen * supported) + sizeof(tp); - - padsize = OFP_ALIGN(tp.tp_length) - tp.tp_length; - tp.tp_length = htons(tp.tp_length); - - if (m_copyback(m, *off, sizeof(tp), (caddr_t)&tp, M_NOWAIT)) - return (OFP_ERRREQ_MULTIPART_OVERFLOW); - *off += sizeof(tp); - - for (i = 0 ; i < nitems(ofp_action_handlers); i++) { - if (ofp_action_handlers[i].action == NULL) - continue; - - memset(&action, 0, actionlen); - action.ah_type = ntohs(ofp_action_handlers[i].action_type); - /* XXX action length is different for experimenter type. */ - action.ah_len = ntohs(actionlen); - - if (m_copyback(m, *off, actionlen, - (caddr_t)&action, M_NOWAIT)) - return (OFP_ERRREQ_MULTIPART_OVERFLOW); - *off += actionlen; - } - - if (padsize) { - memset(padding, 0, padsize); - if (m_copyback(m, *off, padsize, &padding, M_NOWAIT)) - return (OFP_ERRREQ_MULTIPART_OVERFLOW); - - *off += padsize; - } - - return (0); -} - -int -swofp_table_features_put_instruction(struct mbuf *m, int *off, uint16_t tp_type) -{ - struct ofp_table_feature_property tp; - struct ofp_instruction instructions[] = - { - { - htons(OFP_INSTRUCTION_T_GOTO_TABLE), - htons(sizeof(struct ofp_instruction)) - }, - { - htons(OFP_INSTRUCTION_T_WRITE_META), - htons(sizeof(struct ofp_instruction)) - }, - { - htons(OFP_INSTRUCTION_T_WRITE_ACTIONS), - htons(sizeof(struct ofp_instruction)) - }, - { - htons(OFP_INSTRUCTION_T_APPLY_ACTIONS), - htons(sizeof(struct ofp_instruction)) - }, - { - htons(OFP_INSTRUCTION_T_CLEAR_ACTIONS), - htons(sizeof(struct ofp_instruction)) - }, - }; - - tp.tp_type = htons(tp_type); - tp.tp_length = htons(sizeof(instructions) + sizeof(tp)); - - if (m_copyback(m, *off, sizeof(tp), (caddr_t)&tp, M_NOWAIT)) - return (OFP_ERRREQ_MULTIPART_OVERFLOW); - *off += sizeof(tp); - - if (m_copyback(m, *off, sizeof(instructions), - (caddr_t)instructions, M_NOWAIT)) - return (OFP_ERRREQ_MULTIPART_OVERFLOW); - *off += sizeof(instructions); - - return (0); -} - -int -swofp_mp_recv_table_features(struct switch_softc *sc, struct mbuf *m) -{ - struct swofp_ofs *ofs = sc->sc_ofs; - struct swofp_flow_table *swft; - struct ofp_table_features *tblf; - struct mbuf *n; - int off, error; - struct swofp_mpmsg swmp; - - if ((error = swofp_mpmsg_reply_create( - mtod(m, struct ofp_multipart *), &swmp))) - goto error; - - TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) { - /* using mbuf because table features struct is variable length*/ - MGETHDR(n, M_DONTWAIT, MT_DATA); - if (n == NULL) - goto error; - MCLGET(n, M_DONTWAIT); - if ((n->m_flags & M_EXT) == 0) { - m_freem(n); - goto error; - } - n->m_len = n->m_pkthdr.len = sizeof(*tblf); - - tblf = mtod(n, struct ofp_table_features *); - memset(tblf, 0, sizeof(*tblf)); - tblf->tf_tableid = swft->swft_table_id; - tblf->tf_metadata_match = UINT64_MAX; - tblf->tf_metadata_write = UINT64_MAX; - tblf->tf_config = 0; - tblf->tf_max_entries = htonl(ofs->swofs_flow_max_entry); - - off = sizeof(*tblf); - if ((error = swofp_table_features_put_instruction(n, &off, - OFP_TABLE_FEATPROP_INSTRUCTION))) - goto error; - - if ((error = swofp_table_features_put_instruction(n, &off, - OFP_TABLE_FEATPROP_INSTRUCTION_MISS))) - goto error; - - if ((error = swofp_table_features_put_actions(n, &off, - OFP_TABLE_FEATPROP_APPLY_ACTIONS))) - goto error; - - if ((error = swofp_table_features_put_actions(n, &off, - OFP_TABLE_FEATPROP_APPLY_ACTIONS_MISS))) - goto error; - - if ((error = swofp_table_features_put_actions(n, &off, - OFP_TABLE_FEATPROP_WRITE_ACTIONS))) - goto error; - - if ((error = swofp_table_features_put_actions(n, &off, - OFP_TABLE_FEATPROP_WRITE_ACTIONS_MISS))) - goto error; - - if ((error = swofp_table_features_put_oxm(n, &off, - OFP_TABLE_FEATPROP_MATCH))) - goto error; - - if ((error = swofp_table_features_put_oxm(n, &off, - OFP_TABLE_FEATPROP_WILDCARDS))) - goto error; - - if ((error = swofp_table_features_put_oxm(n, &off, - OFP_TABLE_FEATPROP_WRITE_SETFIELD))) - goto error; - - if ((error = swofp_table_features_put_oxm(n, &off, - OFP_TABLE_FEATPROP_WRITE_SETFIELD_MISS))) - goto error; - - if ((error = swofp_table_features_put_oxm(n, &off, - OFP_TABLE_FEATPROP_APPLY_SETFIELD))) - goto error; - - if ((error = swofp_table_features_put_oxm(n, &off, - OFP_TABLE_FEATPROP_APPLY_SETFIELD_MISS))) - goto error; - - tblf->tf_length = htons(n->m_pkthdr.len); - - if ((error = swofp_mpmsg_m_put(&swmp, n))) { - m_freem(n); - goto error; - } - } - - m_freem(m); - return swofp_multipart_reply(sc, &swmp); - - error: - m_freem(m); - swofp_mpmsg_destroy(&swmp); - return (error); -} - -int -swofp_mp_recv_port_desc(struct switch_softc *sc, struct mbuf *m) -{ - struct ofp_switch_port swp; - struct switch_port *swpo; - struct swofp_mpmsg swmp; - struct ifnet *ifs; - int error; - - if ((error = swofp_mpmsg_reply_create( - mtod(m, struct ofp_multipart *), &swmp))) { - m_freem(m); - return (error); - } - - TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) { - memset(&swp, 0, sizeof(swp)); - ifs = if_get(swpo->swpo_ifindex); - if (ifs == NULL) - continue; - - 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); - strlcpy(swp.swp_name, ifs->if_xname, - sizeof(swp.swp_name)); - - if (!ISSET(ifs->if_flags, IFF_UP)) - swp.swp_config |= OFP_PORTCONFIG_PORT_DOWN; - if (!ISSET(swpo->swpo_flags, IFBIF_STP)) - swp.swp_config |= OFP_PORTCONFIG_NO_STP; - swp.swp_config = htonl(swp.swp_config); - - if (!LINK_STATE_IS_UP(ifs->if_data.ifi_link_state)) - swp.swp_state |= OFP_PORTSTATE_LINK_DOWN; - - if_put(ifs); - - swp.swp_state = htonl(swp.swp_state); - /* XXX how to get the if_media from ifp? ioctl? */ - swp.swp_cur = htonl(swp.swp_cur); - swp.swp_advertised = htonl(swp.swp_advertised); - swp.swp_supported = htonl(swp.swp_supported); - swp.swp_peer = htonl(swp.swp_peer); - - if ((error = swofp_mpmsg_put(&swmp, (caddr_t)&swp, - sizeof(swp)))) - goto error; - } - - m_freem(m); - return swofp_multipart_reply(sc, &swmp); - - error: - m_freem(m); - swofp_mpmsg_destroy(&swmp); - return (error); -} - -int -swofp_mp_recv_group_desc(struct switch_softc *sc, struct mbuf *m) -{ - struct ofp_group_desc ogd; - struct swofp_group_entry *swge; - struct swofp_mpmsg swmp; - int error; - - if ((error = swofp_mpmsg_reply_create( - mtod(m, struct ofp_multipart *), &swmp))) - goto failed; - - - LIST_FOREACH(swge, &sc->sc_ofs->swofs_group_table, swge_next) { - memset(&ogd, 0, sizeof(ogd)); - - ogd.gd_length = htons(offsetof(struct ofp_group_desc, - gd_buckets) + swge->swge_buckets_len); - ogd.gd_group_id = htonl(swge->swge_group_id); - ogd.gd_type = swge->swge_type; - - /* - * Copy back GROUP DESC without buckets - */ - if ((error = swofp_mpmsg_put(&swmp, (caddr_t)&ogd, - sizeof(ogd)))) - goto failed; - - /* - * Copy back buckets on GROUP DESC - */ - if (swge->swge_buckets != NULL && - (error = swofp_mpmsg_put(&swmp, (caddr_t)swge->swge_buckets, - swge->swge_buckets_len))) - goto failed; - } - - m_freem(m); - return swofp_multipart_reply(sc, &swmp); - - failed: - m_freem(m); - swofp_mpmsg_destroy(&swmp); - return (error); -} - -int -swofp_barrier_req(struct switch_softc *sc, struct mbuf *m) -{ - swofp_barrier_reply(sc, m); - return 0; -} - -void -swofp_barrier_reply(struct switch_softc *sc, struct mbuf *m) -{ - struct ofp_header *oh; - - oh = mtod(m, struct ofp_header *); - oh->oh_type = OFP_T_BARRIER_REPLY; - - (void)swofp_output(sc, m); -} diff --git a/sys/sys/sockio.h b/sys/sys/sockio.h index 1198dd8728c..e876572e2e2 100644 --- a/sys/sys/sockio.h +++ b/sys/sys/sockio.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sockio.h,v 1.83 2019/11/13 11:54:01 tobhe Exp $ */ +/* $OpenBSD: sockio.h,v 1.84 2021/11/11 10:03:10 claudio Exp $ */ /* $NetBSD: sockio.h,v 1.5 1995/08/23 00:40:47 thorpej Exp $ */ /*- @@ -109,13 +109,6 @@ #define SIOCBRDGGPARAM _IOWR('i', 88, struct ifbropreq)/* get brdg STP parms */ #define SIOCBRDGSTXHC _IOW('i', 89, struct ifbrparam)/* set tx hold count */ #define SIOCBRDGSPROTO _IOW('i', 90, struct ifbrparam)/* set protocol */ -#define SIOCBRDGS - -#define SIOCSWGDPID _IOWR('i', 91, struct ifbrparam)/* get datapath id */ -#define SIOCSWSDPID _IOW('i', 92, struct ifbrparam)/* set datapath id */ -#define SIOCSWGMAXGROUP _IOWR('i', 93, struct ifbrparam)/* get max groups */ -#define SIOCSWSPORTNO _IOWR('i', 95, struct ifbreq) /* set port number */ -#define SIOCSWGMAXFLOW _IOWR('i', 96, struct ifbrparam)/* get max flow per table */ #define SIOCSIFMTU _IOW('i', 127, struct ifreq) /* set ifnet mtu */ #define SIOCGIFMTU _IOWR('i', 126, struct ifreq) /* get ifnet mtu */